/* Returns the value with the lowest priority and removes it from the queue. This is the same as pq_find followed by pq_delete. returns: 1 if successful, 0 if failed (pq is empty) val and priority are returned in the pointers */ int pq_dequeue(struct priority_queue *pq, int *val, int *priority) { if (pq == NULL) return 0; *val = pq->heap[1].val; *priority = pq->heap[1].priority; return pq_delete(pq); }
key_type pq_delete_min( implicit_heap *queue ) { return pq_delete( queue, queue->nodes[0] ); }
int main( int argc, char** argv ) { uint64_t i; // pointers for casting pq_op_create *op_create; pq_op_destroy *op_destroy; pq_op_clear *op_clear; pq_op_get_key *op_get_key; pq_op_get_item *op_get_item; pq_op_get_size *op_get_size; pq_op_insert *op_insert; pq_op_find_min *op_find_min; pq_op_delete *op_delete; pq_op_delete_min *op_delete_min; pq_op_decrease_key *op_decrease_key; //pq_op_meld *op_meld; pq_op_empty *op_empty; // temp dummies for readability pq_type *q;//, *r; pq_node_type *n; if( argc < 2 ) exit( -1 ); int trace_file = open( argv[1], O_RDONLY ); if( trace_file < 0 ) { fprintf( stderr, "Could not open file.\n" ); return -1; } pq_trace_header header; pq_trace_read_header( trace_file, &header ); close( trace_file ); //printf("Header: (%llu,%lu,%lu)\n",header.op_count,header.pq_ids, // header.node_ids); pq_op_blank *ops = calloc( MIN( header.op_count, CHUNK_SIZE ), sizeof( pq_op_blank ) ); pq_type **pq_index = calloc( header.pq_ids, sizeof( pq_type* ) ); pq_node_type **node_index = calloc( header.node_ids, sizeof( pq_node_type* ) ); if( ops == NULL || pq_index == NULL || node_index == NULL ) { fprintf( stderr, "Calloc fail.\n" ); return -1; } #ifdef USE_QUAKE mem_capacities[0] = header.node_ids << 2; #else mem_capacities[0] = header.node_ids; #endif #ifdef USE_EAGER mem_map *map = mm_create( mem_types, mem_sizes, mem_capacities ); #else mem_map *map = mm_create( mem_types, mem_sizes ); #endif uint64_t op_remaining, op_chunk; int status; struct timeval t0, t1; uint32_t iterations = 0; uint32_t total_time = 0; key_type k; //pq_node_type *min; #ifndef CACHEGRIND while( iterations < 5 || total_time < PQ_MIN_USEC ) { mm_clear( map ); iterations++; #endif trace_file = open( argv[1], O_RDONLY ); if( trace_file < 0 ) { fprintf( stderr, "Could not open file.\n" ); return -1; } pq_trace_read_header( trace_file, &header ); op_remaining = header.op_count; while( op_remaining > 0 ) { op_chunk = MIN( CHUNK_SIZE, op_remaining ); op_remaining -= op_chunk; for( i = 0; i < op_chunk; i++ ) { status = pq_trace_read_op( trace_file, ops + i ); if( status == -1 ) { fprintf( stderr, "Invalid operation!" ); return -1; } } #ifndef CACHEGRIND gettimeofday(&t0, NULL); #endif for( i = 0; i < op_chunk; i++ ) { switch( ops[i].code ) { case PQ_OP_CREATE: op_create = (pq_op_create*) ( ops + i ); //printf("pq_create(%d)\n", op_create->pq_id); pq_index[op_create->pq_id] = pq_create( map ); break; case PQ_OP_DESTROY: op_destroy = (pq_op_destroy*) ( ops + i ); //printf("pq_destroy(%d)\n", op_destroy->pq_id); q = pq_index[op_destroy->pq_id]; pq_destroy( q ); pq_index[op_destroy->pq_id] = NULL; break; case PQ_OP_CLEAR: op_clear = (pq_op_clear*) ( ops + i ); //printf("pq_clear(%d)\n", op_clear->pq_id ); q = pq_index[op_clear->pq_id]; pq_clear( q ); break; case PQ_OP_GET_KEY: op_get_key = (pq_op_get_key*) ( ops + i ); //printf("pq_get_key(%d,%d)\n", op_get_key->pq_id, // op_get_key->node_id ); q = pq_index[op_get_key->pq_id]; n = node_index[op_get_key->node_id]; pq_get_key( q, n ); break; case PQ_OP_GET_ITEM: op_get_item = (pq_op_get_item*) ( ops + i ); //printf("pq_get_item(%d,%d)\n", op_get_item->pq_id, // op_get_item->node_id); q = pq_index[op_get_item->pq_id]; n = node_index[op_get_item->node_id]; pq_get_item( q, n ); break; case PQ_OP_GET_SIZE: op_get_size = (pq_op_get_size*) ( ops + i ); //printf("pq_get_size(%d)\n", op_get_size->pq_id); q = pq_index[op_get_size->pq_id]; pq_get_size( q ); break; case PQ_OP_INSERT: op_insert = (pq_op_insert*) ( ops + i ); //printf("pq_insert(%d,%d,%llu,%d)\n", op_insert->pq_id, // op_insert->node_id, op_insert->key, op_insert->item ); q = pq_index[op_insert->pq_id]; node_index[op_insert->node_id] = pq_insert( q, op_insert->item, op_insert->key ); break; case PQ_OP_FIND_MIN: op_find_min = (pq_op_find_min*) ( ops + i ); //printf("pq_find_min(%d)\n", op_find_min->pq_id ); q = pq_index[op_find_min->pq_id]; pq_find_min( q ); break; case PQ_OP_DELETE: op_delete = (pq_op_delete*) ( ops + i ); //printf("pq_delete(%d,%d)\n", op_delete->pq_id, // op_delete->node_id ); q = pq_index[op_delete->pq_id]; n = node_index[op_delete->node_id]; pq_delete( q, n ); break; case PQ_OP_DELETE_MIN: op_delete_min = (pq_op_delete_min*) ( ops + i ); //printf("pq_delete_min(%d)\n", op_delete_min->pq_id); q = pq_index[op_delete_min->pq_id]; //min = pq_find_min( q ); k = pq_delete_min( q ); #ifdef CACHEGRIND if( argc > 2 ) printf("%llu\n",k); #endif break; case PQ_OP_DECREASE_KEY: op_decrease_key = (pq_op_decrease_key*) ( ops + i ); //printf("pq_decrease_key(%d,%d,%llu)\n", op_decrease_key->pq_id, // op_decrease_key->node_id, op_decrease_key->key); q = pq_index[op_decrease_key->pq_id]; n = node_index[op_decrease_key->node_id]; pq_decrease_key( q, n, op_decrease_key->key ); break; /*case PQ_OP_MELD: printf("Meld.\n"); op_meld = (pq_op_meld*) ( ops + i ); q = pq_index[op_meld->pq_src1_id]; r = pq_index[op_meld->pq_src2_id]; pq_index[op_meld->pq_dst_id] = pq_meld( q, r ); break;*/ case PQ_OP_EMPTY: op_empty = (pq_op_empty*) ( ops + i ); //printf("pq_empty(%d)\n", op_empty->pq_id); q = pq_index[op_empty->pq_id]; pq_empty( q ); break; default: break; } //verify_queue( pq_index[0], header.node_ids ); } #ifndef CACHEGRIND gettimeofday(&t1, NULL); total_time += (t1.tv_sec - t0.tv_sec) * 1000000 + (t1.tv_usec - t0.tv_usec); #endif } close( trace_file ); #ifndef CACHEGRIND } #endif for( i = 0; i < header.pq_ids; i++ ) { if( pq_index[i] != NULL ) pq_destroy( pq_index[i] ); } mm_destroy( map ); free( pq_index ); free( node_index ); free( ops ); #ifndef CACHEGRIND printf( "%d\n", total_time / iterations ); #endif return 0; }
/** * Repeatedly merge the closest pair of the given markers until they don't overlap. * * The centroid rule is used for merging. I.e. each marker's area represents * a population of points. Merging two markers removes the originals and creates a * new marker with area the sum of the originals and center at the average position * of the two merged populations. * * The markers array must include extra buffer space. If there are n markers, the * array must have 2n-1 spaces, with only the first n initialized. * * The number of markers after merging is returned. Zero or more of these will be * marked deleted_p and should be ignored. * * This algorithm is O(n k log n), where k is the maximum number of simultaneously * overlapping markers in the original, unmerged set. */ int merge_markers_fast(MARKER_INFO *info, MARKER *markers, int n_markers) { int augmented_length = 2 * n_markers - 1; NewArrayDecl(int, n_nghbr, augmented_length); NewArrayDecl(MARKER_DISTANCE, mindist, augmented_length); NewArrayDecl(int, inv_nghbr_head, augmented_length); NewArrayDecl(int, inv_nghbr_next, augmented_length); NewArrayDecl(int, tmp, augmented_length); // Too big // Do not free the following array! It's owned by the priority queue. NewArrayDecl(int, heap, augmented_length); // Too big // Specialized quadtree supports finding closest marker to any given one. QUADTREE_DECL(qt); // Priority queue keyed on distances of overlapping pairs of markers. PRIORITY_QUEUE_DECL(pq); /// Extent of markers in the domain. MARKER_EXTENT ext[1]; // Get a bounding box for the whole collection of markers. get_marker_array_extent(markers, n_markers, ext); // Set up the quadtree with the bounding box. Choose tree depth heuristically. int max_depth = high_bit_position(n_markers) / 4 + 3; qt_setup(qt, max_depth, ext->x, ext->y, ext->w, ext->h, info); // Insert all the markers in the quadtree. for (int i = 0; i < n_markers; i++) qt_insert(qt, markers + i); // Set all the inverse nearest neighbor links to null. for (int i = 0; i < augmented_length; i++) inv_nghbr_head[i] = inv_nghbr_next[i] = -1; // Initialize the heap by adding an index for each overlapping pair. The // The heap holds indices into the array of min-distance keys. An index for // pair a->bis added iff markers with indices a and b overlap and b < a. int heap_size = 0; for (int a = 0; a < n_markers; a++) { int b = qt_nearest_wrt(markers, qt, a); if (0 <= b && b < a) { n_nghbr[a] = b; mindist[a] = mr_distance(info, markers + a, markers + b); heap[heap_size++] = a; // Here we are building a linked list of markers that have b as nearest. inv_nghbr_next[a] = inv_nghbr_head[b]; inv_nghbr_head[b] = a; } } // Now install the raw heap array into the priority queue. After this it's owned by the queue. pq_set_up_heap(pq, heap, heap_size, mindist, augmented_length); // Too big while (!pq_empty_p(pq)) { // Get nearest pair from priority queue. int a = pq_get_min(pq); int b = n_nghbr[a]; // Delete both of the nearest pair from all data structures. pq_delete(pq, b); qt_delete(qt, markers + a); qt_delete(qt, markers + b); mr_set_deleted(markers + a); mr_set_deleted(markers + b); // Capture the inv lists of both a and b in tmp. int tmp_size = 0; for (int p = inv_nghbr_head[a]; p >= 0; p = inv_nghbr_next[p]) if (!markers[p].deleted_p) tmp[tmp_size++] = p; for (int p = inv_nghbr_head[b]; p >= 0; p = inv_nghbr_next[p]) if (!markers[p].deleted_p) tmp[tmp_size++] = p; // Create a new merged marker. Adding it after all others means // nothing already in the heap could have it as nearest. int aa = n_markers++; mr_merge(info, markers, aa, a, b); // Add to quadtree. qt_insert(qt, markers + aa); // Find nearest overlapping neighbor of the merged marker, if any. int bb = qt_nearest_wrt(markers, qt, aa); if (0 <= bb) { n_nghbr[aa] = bb; mindist[aa] = mr_distance(info, markers + aa, markers + bb); pq_add(pq, aa); inv_nghbr_next[aa] = inv_nghbr_head[bb]; inv_nghbr_head[bb] = aa; } // Reset the nearest neighbors of the inverse neighbors of the deletions. for (int i = 0; i < tmp_size; i++) { int aa = tmp[i]; int bb = qt_nearest_wrt(markers, qt, aa); if (0 <= bb && bb < aa) { n_nghbr[aa] = bb; mindist[aa] = mr_distance(info, markers + aa, markers + bb); pq_update(pq, aa); inv_nghbr_next[aa] = inv_nghbr_head[bb]; inv_nghbr_head[bb] = aa; } else { pq_delete(pq, aa); } } } qt_clear(qt); pq_clear(pq); Free(n_nghbr); Free(mindist); Free(inv_nghbr_head); Free(inv_nghbr_next); Free(tmp); return n_markers; }
// Return the top of the queue int pq_dequeue(prio_q* pq) { int n = pq_delete(pq, 0); return n; }