Пример #1
0
 /**
  * Determine if no points are found
  *
  * @return True if no points added
  */
 bool empty() const {
   return m_q.empty();
 }
Пример #2
0
 inline T get() {
   T best_item = elements.top().second;
   elements.pop();
   return best_item;
 }
Пример #3
0
 tripoint get_next() {
     auto pt = open.top();
     open.pop();
     return pt.second;
 }
Пример #4
0
 inline bool empty(void) const
 {
     return data.empty();
 }
Пример #5
0
 inline bool empty() { return elements.empty(); }
void AggregatingSortedBlockInputStream::merge(MutableColumns & merged_columns, std::priority_queue<SortCursor> & queue)
{
    size_t merged_rows = 0;

    /// We take the rows in the correct order and put them in `merged_block`, while the rows are no more than `max_block_size`
    while (!queue.empty())
    {
        SortCursor current = queue.top();

        setPrimaryKeyRef(next_key, current);

        bool key_differs;

        if (current_key.empty())    /// The first key encountered.
        {
            setPrimaryKeyRef(current_key, current);
            key_differs = true;
        }
        else
            key_differs = next_key != current_key;

        /// if there are enough rows accumulated and the last one is calculated completely
        if (key_differs && merged_rows >= max_block_size)
            return;

        queue.pop();

        if (key_differs)
        {
            current_key.swap(next_key);

            /// We will write the data for the group. We copy the values of ordinary columns.
            for (size_t i = 0, size = column_numbers_not_to_aggregate.size(); i < size; ++i)
            {
                size_t j = column_numbers_not_to_aggregate[i];
                merged_columns[j]->insertFrom(*current->all_columns[j], current->pos);
            }

            /// Add the empty aggregation state to the aggregate columns. The state will be updated in the `addRow` function.
            for (auto & column_to_aggregate : columns_to_aggregate)
                column_to_aggregate->insertDefault();

            ++merged_rows;
        }

        addRow(current);

        if (!current->isLast())
        {
            current->next();
            queue.push(current);
        }
        else
        {
            /// We fetch the next block from the appropriate source, if there is one.
            fetchNextBlock(current, queue);
        }
    }

    finished = true;
}
Пример #7
0
void AddToHeaps(std::priority_queue<double, std::vector<double>, std::greater<double> >& m,
		std::priority_queue<double>& M, double x){

	// decide on initial heap to place element into
	if(m.empty() || x < m.top())
		M.push(x);
	else
		m.push(x);
	// make sure that heaps are balanced
	if(m.size() > M.size() + 1){
		M.push( m.top() );
		m.pop();	
	}
	else if(M.size() > m.size() + 1){
		m.push( M.top() );
		M.pop();
	}
}
Пример #8
0
void checkCollision() {
    int i, j;
    if ( events.size()!=0) {
        while( elapsedTime >= events.top().timeOccuring)
        {
            i = events.top().i;

            if( checkOutdated( events.top() ) ) {
                printf("---POOPZIES of %d, timeInserted=%f, lastCollition=%f\n",
                       i, events.top().timeInserted, sphere[i].lastCollision );
                events.pop();
            } else if (events.top().j!=-1) {
                j = events.top().j;

                sphere[i].q0 += (events.top().timeOccuring - sphere[i].t0) * sphere[i].speedVec;
                sphere[i].speedVec = sphere[i].newSpeedVec;
                sphere[i].t0 = events.top().timeOccuring;

                sphere[j].q0 += (events.top().timeOccuring - sphere[j].t0) * sphere[j].speedVec;
                sphere[j].speedVec = sphere[j].newSpeedVec;
                sphere[j].t0 = events.top().timeOccuring;

                sphere[i].cols++;
                sphere[j].cols++;

                events.pop();
                calculateCollision(i);
                calculateCollision(j);
                printf("BALLZIES of %d, timeInserted=%f, lastCollition=%f\n",
                       i, events.top().timeInserted, sphere[i].lastCollision );
            } else {
                sphere[i].q0 += (events.top().timeOccuring - sphere[i].t0) * sphere[i].speedVec;
                sphere[i].speedVec = sphere[i].newSpeedVec;
                sphere[i].t0 = events.top().timeOccuring;

                sphere[i].cols++;

                events.pop();
                calculateCollision(i);
                printf("WALLZIES of %d, timeInserted=%f, lastCollition=%f\n",
                       i, events.top().timeInserted, sphere[i].lastCollision );
            }
        }
        //std::vector<Sphere>::iterator it = sphereIterInit;
        //for(it; it != sphere.end();it++){
        //	position = it->q0 + (float)(elapsedTime - it->t0) * it->speedVec;
        //	if(abs(position.x)>0.96f || abs(position.y)>0.96f || abs(position.z)>0.96f){
        //		printf("WHAT THE F**K MOAR BUGS PLS!!!!!AAAAAAAAAAARRGGH\n");
        //	}
        //}


        minmin = (events.top().timeOccuring<minmin)?events.top().timeOccuring:minmin;
    }
}
Пример #9
0
 void pop()
 {
     _pq.pop();
 }
Пример #10
0
 Cell top() const
 {
     return _pq.top().cell;
 }
Пример #11
0
void dijkstra_pq_thread(CSRGraph *g, int *dist, std::priority_queue<Priority_struct, std::vector<Priority_struct>, Compare_priority> &pq, int threadNum, std::mutex *dist_locks)
{
    while(!pq.empty())
    {
        queue_lock.lock();

        if(pq.empty())
        {
            queue_lock.unlock();
            break;
        }

        Priority_struct temp_struct = pq.top();
        int u = temp_struct.node_name;
        pq.pop();
	
    printf("Popped\n");
    for(int i=0; i< pq.size();i++){
	printf(" %d", pq[i]);
    }
    printf("\n");

        int udist = dist[u];

        queue_lock.unlock();

        std::vector<int> neighbors = CSRGraph_getNeighbors(g, u);

        int neighbor;
        for(neighbor=0;neighbor < neighbors.size(); neighbor++)
        {
            int v = neighbors[neighbor];
            int uvdist = CSRGraph_getDistance(g, u, v);
            int alt = udist + uvdist;

            dist_locks[v].lock();
            if(alt < dist[v])
            {
                dist[v] = alt;
                dist_locks[v].unlock();

                Priority_struct temp2;
                temp2.node_name=v;
                temp2.node_weight = uvdist;

                queue_lock.lock();                
                pq.push(temp2);
		
    printf("Pushed\n");
    for(int i=0; i< pq.size();i++){
	printf(" %d", pq[i]);
    }
    printf("\n");
                queue_lock.unlock();                    
            }
            else
            {
                dist_locks[v].unlock();
            }
        }
    }

    //printf("Thread %d ended.\n", threadNum);
}
Пример #12
0
 void push(Cell const& cell, Value const& value)
 {
     _pq.push(Entry(cell, value, ++_count));
 }
void MergingSortedBlockInputStream::merge(Block & merged_block, ColumnPlainPtrs & merged_columns, std::priority_queue<TSortCursor> & queue)
{
	size_t merged_rows = 0;

	/** Увеличить счётчики строк.
	  * Вернуть true, если пора закончить формировать текущий блок данных.
	  */
	auto count_row_and_check_limit = [&, this]()
	{
		++total_merged_rows;
		if (limit && total_merged_rows == limit)
		{
	//		std::cerr << "Limit reached\n";
			cancel();
			finished = true;
			return true;
		}

		++merged_rows;
		if (merged_rows == max_block_size)
		{
	//		std::cerr << "max_block_size reached\n";
			return true;
		}

		return false;
	};

	/// Вынимаем строки в нужном порядке и кладём в merged_block, пока строк не больше max_block_size
	while (!queue.empty())
	{
		TSortCursor current = queue.top();
		queue.pop();

		while (true)
		{
			/** А вдруг для текущего курсора блок целиком меньше или равен, чем остальные?
			  * Или в очереди остался только один источник данных? Тогда можно целиком взять блок текущего курсора.
			  */
			if (current.impl->isFirst() && (queue.empty() || current.totallyLessOrEquals(queue.top())))
			{
	//			std::cerr << "current block is totally less or equals\n";

				/// Если в текущем блоке уже есть данные, то сначала вернём его. Мы попадём сюда снова при следующем вызове функции merge.
				if (merged_rows != 0)
				{
	//				std::cerr << "merged rows is non-zero\n";
					queue.push(current);
					return;
				}

				/// Actually, current.impl->order stores source number (i.e. cursors[current.impl->order] == current.impl)
				size_t source_num = current.impl->order;

				if (source_num >= cursors.size())
					throw Exception("Logical error in MergingSortedBlockInputStream", ErrorCodes::LOGICAL_ERROR);

				for (size_t i = 0; i < num_columns; ++i)
					merged_block.getByPosition(i).column = source_blocks[source_num]->getByPosition(i).column;

	//			std::cerr << "copied columns\n";

				size_t merged_rows = merged_block.rows();

				if (limit && total_merged_rows + merged_rows > limit)
				{
					merged_rows = limit - total_merged_rows;
					for (size_t i = 0; i < num_columns; ++i)
					{
						auto & column = merged_block.getByPosition(i).column;
						column = column->cut(0, merged_rows);
					}

					cancel();
					finished = true;
				}

				if (out_row_sources)
					out_row_sources->resize_fill(out_row_sources->size() + merged_rows, RowSourcePart(source_num));

	//			std::cerr << "fetching next block\n";

				total_merged_rows += merged_rows;
				fetchNextBlock(current, queue);
				return;
			}

	//		std::cerr << "total_merged_rows: " << total_merged_rows << ", merged_rows: " << merged_rows << "\n";
	//		std::cerr << "Inserting row\n";
			for (size_t i = 0; i < num_columns; ++i)
				merged_columns[i]->insertFrom(*current->all_columns[i], current->pos);

			if (out_row_sources)
			{
				/// Actually, current.impl->order stores source number (i.e. cursors[current.impl->order] == current.impl)
				out_row_sources->emplace_back(current.impl->order);
			}

			if (!current->isLast())
			{
	//			std::cerr << "moving to next row\n";
				current->next();

				if (queue.empty() || !(current.greater(queue.top())))
				{
					if (count_row_and_check_limit())
					{
	//					std::cerr << "pushing back to queue\n";
						queue.push(current);
						return;
					}

					/// Не кладём курсор обратно в очередь, а продолжаем работать с текущим курсором.
	//				std::cerr << "current is still on top, using current row\n";
					continue;
				}
				else
				{
	//				std::cerr << "next row is not least, pushing back to queue\n";
					queue.push(current);
				}
			}
			else
			{
				/// Достаём из соответствующего источника следующий блок, если есть.
	//			std::cerr << "It was last row, fetching next block\n";
				fetchNextBlock(current, queue);
			}

			break;
		}

		if (count_row_and_check_limit())
			return;
	}

	cancel();
	finished = true;
}
void MergingSortedBlockInputStream::initQueue(std::priority_queue<TSortCursor> & queue)
{
	for (size_t i = 0; i < cursors.size(); ++i)
		if (!cursors[i].empty())
			queue.push(TSortCursor(&cursors[i]));
}
void AggregatingSortedBlockInputStream::merge(ColumnPlainPtrs & merged_columns, std::priority_queue<TSortCursor> & queue)
{
	size_t merged_rows = 0;

	/// Вынимаем строки в нужном порядке и кладём в merged_block, пока строк не больше max_block_size
	while (!queue.empty())
	{
		TSortCursor current = queue.top();

		setPrimaryKeyRef(next_key, current);

		bool key_differs;

		if (current_key.empty())	/// Первый встретившийся ключ.
		{
			current_key.columns.resize(description.size());
			setPrimaryKeyRef(current_key, current);
			key_differs = true;
		}
		else
			key_differs = next_key != current_key;

		/// если накопилось достаточно строк и последняя посчитана полностью
		if (key_differs && merged_rows >= max_block_size)
			return;

		queue.pop();

		if (key_differs)
		{
			current_key.swap(next_key);

			/// Запишем данные для очередной группы. Копируем значения обычных столбцов.
			for (size_t i = 0, size = column_numbers_not_to_aggregate.size(); i < size; ++i)
			{
				size_t j = column_numbers_not_to_aggregate[i];
				merged_columns[j]->insertFrom(*current->all_columns[j], current->pos);
			}

			/// Добавляем в агрегатные столбцы пустое состояние агрегации. Состояние будет обновлено в функции addRow.
			for (auto & column_to_aggregate : columns_to_aggregate)
				column_to_aggregate->insertDefault();

			++merged_rows;
		}

		addRow(current);

		if (!current->isLast())
		{
			current->next();
			queue.push(current);
		}
		else
		{
			/// Достаём из соответствующего источника следующий блок, если есть.
			fetchNextBlock(current, queue);
		}
	}

	finished = true;
}
Пример #16
0
 Cell top() const
 {
     return _pq.top().vertex;
 }
Пример #17
0
void pintar_vertices(Grafo& g,  std::priority_queue<Vertice, std::vector<Vertice>, std::greater<Vertice> >& vertices) { //std::priority_queue<Vertice> vertices) {
  init_time();
  int vistos = 0;
  int cant_vertices = g.cant_vertices();
  // Creo vector para obtener el maximo
  for (int i = 0 ; i < cant_vertices ; ++i) {
    vertices.push(g.dame_vertice(i));
  }

  // Recorro todos los vertices del grafo
  while (vistos < cant_vertices) {
    //std::cout << "vistos: " << vistos << " cant_vertices " << cant_vertices << std::endl;

    // Hallar el vertice de mayor grado
    Vertice vertice = vertices.top();
    // std::cout << "vertice: " << vertice.dame_nombre() << std::endl;
    vertices.pop();
    std::set<int> colores_vertice = vertice.dame_colores_posibles(); 

    // Creo un diccionario para ver cual es el color 
    // que mas usan los vecinos 
    // y otro para ver cual es el que mas se repite entre los 
    // colores posibles de los vecinos
    std::map<int, int> colores_usados;
    std::map<int, int> colores_posibles;
    for (int color : colores_vertice) {
      colores_usados.insert(std::pair<int, int> (color, 0));
      colores_posibles.insert(std::pair<int, int> (color, 0));
    }

    // recorro los vecinos del maximo
    std::set<int> vecinos = g.dame_vecinos(vertice.dame_nombre());
    for (int v : vecinos) {

      int color_vecino = g.dame_color(v);
      if (color_vecino != -1) { // Ya esta pintado el vecino y no puedo usar ese color
        // Me fijo si el vertice sobre el cual estoy parado tiene a ese 
        // color como disponible y de ser así lo aumento en el diccionario de colores
        std::set<int>::iterator it = colores_vertice.find(color_vecino);
        if (it != colores_vertice.end())
          colores_usados[color_vecino]++;

      } else {
        // Si no esta pintado el vecino
        std::set<int> colores_vecino = g.dame_colores_posibles(v);

        // Por cada color que entre en conflicto sumo 1 en el diccionario
        for (int color : colores_vecino) {
          std::set<int>::iterator it = colores_vertice.find(color);
          if (it != colores_vertice.end()) {
            colores_posibles[color]++;
          }
        }
      }
    }
    // Tengo dos diccionarios que determinan para cada color que tiene el vértice
    // la cantidad de vecinos que tienen ese color pintado
    // y la cantidad de vecinos que tienen ese color como posibilidad
    
    // Recorro el diccionario de colores usados por mis vecinos 
    for (int i = 0 ; i < colores_usados.size() ; ++i) {
      if (colores_vertice.size() > 1) {
        // Elijo el color que es el mas utilizado por mis vecinos
        int color_con_mas_apariciones = dame_el_de_maxima_aparicion(colores_usados);
        // Lo borro
        if (color_con_mas_apariciones != -1 )
          colores_vertice.erase(color_con_mas_apariciones);
      }
    }

    // O salgo del for anterior con muchos colores disponibles porque mis vecinos no
    // estaban pintados
    // o tengo un único color disponible para pintarme
    int color;
    if (colores_vertice.size() == 1) {
      // Si me queda un único color en mi conjunto es el que menos conflictos me causaba
      // por ende pinto al grafo de esa manera
      std::set<int>::iterator it = colores_vertice.begin();
      color = *it;
    } else {
      // Si me queda más de un color disponible busco en los posibles colores 
      // de mis vecinos el que quizas me trae menos conflictos
      int min = 999;
      for (std::pair<const int, int>& par : colores_posibles) {
        if (par.second < min) {
          std::set<int>::iterator it = colores_vertice.find(par.first);
          if (it != colores_vertice.end()) {
            min = par.second;
            color = par.first;
          }
        }
      }
    }
    g.pintar(vertice.dame_nombre(), color);
    //g.imprimir();
    vistos++;
  }
  acum += get_time(); 
}
Пример #18
0
 bool empty() const
 {
     return _pq.empty();
 }
Пример #19
0
int main() {
    scanf("%d %d", &n, &m);
    for (int i = 0; i < m; i++) {
        scanf("%d %d %d", &a, &b, &t);
        adj[a].push_back(std::make_pair(b, t));
        adj[b].push_back(std::make_pair(a, t));
    }
    
    dist[0] = 0;
    q.push(std::make_pair(0, 0));
    for (int i = 1; i < n; i++) {
        dist[i] = 0x3f3f3f3f;
        q.push(std::make_pair(-dist[i], i));
    }
    
    while (!q.empty()) {
        std::tie(cur_dist, cur_index) = q.top(); q.pop();
        cur_dist *= -1;
        vis[cur_index] = 1;
        for (std::pair<int, int> p : adj[cur_index]) {
            if (!vis[p.first]) {
                const int alt = cur_dist + p.second;
                if (alt < dist[p.first]) {
                    dist[p.first] = alt;
                    q.push(std::make_pair(-alt, p.first));
                }
            }
        }
    }

    dist2[0] = 0;
    q.push(std::make_pair(0, n - 1));
    for (int i = 0; i < n - 1; i++) {
        dist2[i] = 0x3f3f3f3f;
        q.push(std::make_pair(-dist2[i], i));
    }

    while (!q.empty()) {
        std::tie(cur_dist, cur_index) = q.top(); q.pop();
        cur_dist *= -1;
        vis2[cur_index] = 1;
        for (std::pair<int, int> p : adj[cur_index]) {
            if (!vis2[p.first]) {
                const int alt = cur_dist + p.second;
                if (alt < dist2[p.first]) {
                    dist2[p.first] = alt;
                    q.push(std::make_pair(-alt, p.first));
                }
            }
        }
    }
    
    for (int i = 0; i < n; i++) {
        ans = std::max(ans, dist[i] + dist2[i]);
    }
    printf("%d\n", ans);
}
Пример #20
0
 void push(Cell const& vertex, Value const& value)
 {
     _pq.push(Entry(vertex, value, ++_count));
 }
Пример #21
0
 inline size_t size(void) const
 {
     return data.size();
 }
Пример #22
0
void BiDirDijkstra::explore(int cur_node, double cur_cost, int dir, std::priority_queue<PDI, std::vector<PDI>, std::greater<PDI> > &que)
{
	int i;
	// Number of connected edges
	int con_edge = m_vecNodeVector[cur_node]->Connected_Edges_Index.size();
	double edge_cost;

	for(i = 0; i < con_edge; i++)
	{
		int edge_index = m_vecNodeVector[cur_node]->Connected_Edges_Index[i];
		// Get the edge from the edge list.
		GraphEdgeInfo edge = m_vecEdgeVector[edge_index];
		// Get the connected node
		int new_node = m_vecNodeVector[cur_node]->Connected_Nodes[i];
		
		if(cur_node == edge.StartNode)
		{
			// Current node is the startnode of the edge. For forward search it should use forward cost, otherwise it should use the reverse cost,
			// i.e. if the reverse direction is valid then this node may be visited from the end node.
			if(dir > 0)
				edge_cost = edge.Cost;
			else
				edge_cost = edge.ReverseCost;

			// Check if the direction is valid for exploration
			if(edge.Direction == 0 || edge_cost >= 0.0)
			{			
				// Check if the current edge gives better result
				if(cur_cost + edge_cost < getcost(new_node, dir))
				{
					// explore the node, and push it in the queue
					setcost(new_node, dir, cur_cost + edge_cost);
					setparent(new_node, dir, cur_node, edge.EdgeID);
					que.push(std::make_pair(cur_cost + edge_cost, new_node));

					// Update the minimum cost found so far.
					if(getcost(new_node, dir) + getcost(new_node, dir * -1) < m_MinCost)
					{
						m_MinCost = getcost(new_node, dir) + getcost(new_node, dir * -1);
						m_MidNode = new_node;
					}
				}
			}
		}
		else
		{
			// Current node is the endnode of the edge. For forward search it should use reverse cost, otherwise it should use the forward cost,
			// i.e. if the forward direction is valid then this node may be visited from the start node.
			if(dir > 0)
				edge_cost = edge.ReverseCost;
			else
				edge_cost = edge.Cost;

			// Check if the direction is valid for exploration
			if(edge.Direction == 0 || edge_cost >= 0.0)
			{
				// Check if the current edge gives better result
				if(cur_cost + edge_cost < getcost(new_node, dir))
				{
					setcost(new_node, dir, cur_cost + edge_cost);
					setparent(new_node, dir, cur_node, edge.EdgeID);
					que.push(std::make_pair(cur_cost + edge_cost, new_node));

					// Update the minimum cost found so far.
					if(getcost(new_node, dir) + getcost(new_node, dir * -1) < m_MinCost)
					{
						m_MinCost = getcost(new_node, dir) + getcost(new_node, dir * -1);
						m_MidNode = new_node;
					}
				}
			}
		}
	}
}
Пример #23
0
void HClustNNbasedSingle::computeMerge(
      std::priority_queue< HeapHierarchicalItem > & pq,
      HClustResult& res)
{
   MESSAGE_2("[%010.3f] merging clusters\n", clock()/(float)CLOCKS_PER_SEC);

   volatile bool go=true;
   volatile size_t i = 0;
#ifdef _OPENMP
   #pragma omp parallel
#endif
   while (go)
   {
#ifdef _OPENMP
      omp_set_lock(&pqwritelock);
#endif
      STOPIFNOT(!pq.empty())
      HeapHierarchicalItem hhi = pq.top();

      if (hhi.index2 == SIZE_MAX) {
         pq.pop();
#ifdef _OPENMP
         omp_unset_lock(&pqwritelock);
#endif
         getNearestNeighbors(pq, hhi.index1);
         continue;
      }

      size_t s1 = ds.find_set(hhi.index1);
      size_t s2 = ds.find_set(hhi.index2);

      if (s1 == s2)
      {
         pq.pop();
#ifdef _OPENMP
         omp_unset_lock(&pqwritelock);
#endif
         continue;
      }

#ifdef _OPENMP
      omp_unset_lock(&pqwritelock); //different threads will be unable to put data into pq without it
      #pragma omp barrier
      #pragma omp single
#endif
      {
         hhi = pq.top(); //it can change, because other threads can push something
         pq.pop();
         s1 = ds.find_set(hhi.index1);
         s2 = ds.find_set(hhi.index2);
         STOPIFNOT(s1 != s2);
         STOPIFNOT(s2 != SIZE_MAX);
         STOPIFNOT(hhi.index1 < hhi.index2);

         res.link(indices[hhi.index1], indices[hhi.index2], hhi.dist);
         ds.link(s1, s2);

         ++i;
         if (i == n-1)
            go = false;/* avoids computing unnecessary nn */
      } // #pragma omp single
      if (MASTER_OR_SINGLE_THREAD) {
         if (i % 512 == 0) MESSAGE_7("\r             merge clusters: %d / %d", i+1, n-1);
         Rcpp::checkUserInterrupt(); // may throw an exception, fast op, not thread safe
      }
   }

   MESSAGE_7("\r             merge clusters: %d / %d  \n", n-1, n-1);
   Rcpp::checkUserInterrupt();
}
Пример #24
0
	void Push(T e) { data.push(e); }
Пример #25
0
 inline void put(T item, Number priority) {
   elements.emplace(priority, item);
 }
Пример #26
0
	T Pop() { auto v = data.top(); data.pop(); return v; }
Пример #27
0
 bool empty() const {
     return open.empty();
 }
Пример #28
0
	bool Empty() { return data.empty(); }
Пример #29
0
namespace DeviceTime {

////////////////////////////////////////////////////////////////////////////////
/// Queue of Virtual Devices
static std::priority_queue<double,
                           std::vector<double>,
                           std::greater<double> > QUEUE;

////////////////////////////////////////////////////////////////////////////////
/// Mutex Lock
static std::mutex MUTEX;
static std::condition_variable CONDVAR;

////////////////////////////////////////////////////////////////////////////////
/// Wait for correct time to elapse if REALTIME is true
static bool REALTIME = false;

////////////////////////////////////////////////////////////////////////////////
/// TO_READ can be used to step through and pause events
static std::atomic<uint64_t> EVENTS_TO_QUEUE(
    std::numeric_limits<uint64_t>::max());

////////////////////////////////////////////////////////////////////////////////
inline bool IsPaused()
{
    return EVENTS_TO_QUEUE == 0;
}

////////////////////////////////////////////////////////////////////////////////
void ResetTime()
{
    std::lock_guard<std::mutex> lock(MUTEX);
    // clear queue
    QUEUE = std::priority_queue< double, std::vector<double>, std::greater<double> >();
}

////////////////////////////////////////////////////////////////////////////////
double NextTime()
{
    //std::lock_guard<std::mutex> lock(MUTEX);
    if( QUEUE.empty() ) {
        return 0;
    } else {
        return QUEUE.top();
    }
}

////////////////////////////////////////////////////////////////////////////////
void WaitForTime(double nextTime)
{
    // check if timestamp is the top of the queue
    // if not, wait until the older timestamp is popped by another thread.
    std::unique_lock<std::mutex> lock(MUTEX);
    CONDVAR.wait( lock, [=]{return  NextTime() >= nextTime;});

    // TODO: Sleep for appropriate amount of time.
    if(REALTIME) {
        std::this_thread::sleep_for(std::chrono::milliseconds(1));
    }
}

////////////////////////////////////////////////////////////////////////////////
void PushTime( double T )
{
    // don't push in bad times
    // (0 is a special time when no timestamps are in use)
    if( T >= 0 ) {
        std::lock_guard<std::mutex> lock(MUTEX);
        QUEUE.push( T );
    }
}

////////////////////////////////////////////////////////////////////////////////
void PopAndPushTime( double T )
{
    std::unique_lock<std::mutex> lock(MUTEX);

    // Hold up the device at the top of the queue whilst time is 'paused'
    while(IsPaused()) {
        CONDVAR.wait( lock );
    }

    // pop top of queue which is what got us the lock in the first place!
    QUEUE.pop();

    // don't push in bad times
    // (0 is a special time when no timestamps are in use)
    if( T >= 0 ) {
        QUEUE.push( T );
    }

    // Signify that event has been queued
    EVENTS_TO_QUEUE--;

    // notify waiting threads that a change in the QUEUE has occured
    CONDVAR.notify_all();
}

////////////////////////////////////////////////////////////////////////////////
void PopTime()
{
    std::lock_guard<std::mutex> lock(MUTEX);
    QUEUE.pop();

    // notify waiting threads that a change in the QUEUE has occured
    CONDVAR.notify_all();
}

////////////////////////////////////////////////////////////////////////////////
void SetRealtime(bool realtime)
{
    REALTIME = realtime;
}

////////////////////////////////////////////////////////////////////////////////
void PauseTime()
{
    std::lock_guard<std::mutex> lock(MUTEX);

    EVENTS_TO_QUEUE = 0;
}

////////////////////////////////////////////////////////////////////////////////
void UnpauseTime()
{
    std::lock_guard<std::mutex> lock(MUTEX);

    EVENTS_TO_QUEUE = std::numeric_limits<uint64_t>::max();

    // notify waiting threads that a change in the QUEUE has occured
    CONDVAR.notify_all();
}

////////////////////////////////////////////////////////////////////////////////
void TogglePauseTime()
{
    std::lock_guard<std::mutex> lock(MUTEX);

    if(IsPaused()) {
        // unpause
        EVENTS_TO_QUEUE = std::numeric_limits<uint64_t>::max();
        CONDVAR.notify_all();
    }else{
        // pause
        EVENTS_TO_QUEUE = 0;
    }
}

////////////////////////////////////////////////////////////////////////////////
void StepTime(int numEvents)
{
    std::lock_guard<std::mutex> lock(MUTEX);
    EVENTS_TO_QUEUE = numEvents;
    CONDVAR.notify_all();
}




}
void BinarySpaceTree<MetricType, StatisticType, MatType, BoundType, SplitType>::
BreadthFirstDualTreeTraverser<RuleType>::Traverse(
    BinarySpaceTree<MetricType, StatisticType, MatType, BoundType, SplitType>&
        queryNode,
    std::priority_queue<QueueFrameType>& referenceQueue)
{
  // Store queues for the children.  We will recurse into the children once our
  // queue is empty.
  std::priority_queue<QueueFrameType> leftChildQueue;
  std::priority_queue<QueueFrameType> rightChildQueue;

  while (!referenceQueue.empty())
  {
    QueueFrameType currentFrame = referenceQueue.top();
    referenceQueue.pop();

    BinarySpaceTree& queryNode = *currentFrame.queryNode;
    BinarySpaceTree& referenceNode = *currentFrame.referenceNode;
    typename RuleType::TraversalInfoType ti = currentFrame.traversalInfo;
    rule.TraversalInfo() = ti;
    const size_t queryDepth = currentFrame.queryDepth;

    double score = rule.Score(queryNode, referenceNode);
    ++numScores;

    if (score == DBL_MAX)
    {
      ++numPrunes;
      continue;
    }

    // If both are leaves, we must evaluate the base case.
    if (queryNode.IsLeaf() && referenceNode.IsLeaf())
    {
      // Loop through each of the points in each node.
      const size_t queryEnd = queryNode.Begin() + queryNode.Count();
      const size_t refEnd = referenceNode.Begin() + referenceNode.Count();
      for (size_t query = queryNode.Begin(); query < queryEnd; ++query)
      {
        // See if we need to investigate this point (this function should be
        // implemented for the single-tree recursion too).  Restore the
        // traversal information first.
//        const double childScore = rule.Score(query, referenceNode);

//        if (childScore == DBL_MAX)
//          continue; // We can't improve this particular point.

        for (size_t ref = referenceNode.Begin(); ref < refEnd; ++ref)
          rule.BaseCase(query, ref);

        numBaseCases += referenceNode.Count();
      }
    }
    else if ((!queryNode.IsLeaf()) && referenceNode.IsLeaf())
    {
      // We have to recurse down the query node.
      QueueFrameType fl = { queryNode.Left(), &referenceNode, queryDepth + 1,
          score, rule.TraversalInfo() };
      leftChildQueue.push(fl);

      QueueFrameType fr = { queryNode.Right(), &referenceNode, queryDepth + 1,
          score, ti };
      rightChildQueue.push(fr);
    }
    else if (queryNode.IsLeaf() && (!referenceNode.IsLeaf()))
    {
      // We have to recurse down the reference node.  In this case the recursion
      // order does matter.  Before recursing, though, we have to set the
      // traversal information correctly.
      QueueFrameType fl = { &queryNode, referenceNode.Left(), queryDepth,
          score, rule.TraversalInfo() };
      referenceQueue.push(fl);

      QueueFrameType fr = { &queryNode, referenceNode.Right(), queryDepth,
          score, ti };
      referenceQueue.push(fr);
    }
    else
    {
      // We have to recurse down both query and reference nodes.  Because the
      // query descent order does not matter, we will go to the left query child
      // first.  Before recursing, we have to set the traversal information
      // correctly.
      QueueFrameType fll = { queryNode.Left(), referenceNode.Left(),
          queryDepth + 1, score, rule.TraversalInfo() };
      leftChildQueue.push(fll);

      QueueFrameType flr = { queryNode.Left(), referenceNode.Right(),
          queryDepth + 1, score, rule.TraversalInfo() };
      leftChildQueue.push(flr);

      QueueFrameType frl = { queryNode.Right(), referenceNode.Left(),
          queryDepth + 1, score, rule.TraversalInfo() };
      rightChildQueue.push(frl);

      QueueFrameType frr = { queryNode.Right(), referenceNode.Right(),
          queryDepth + 1, score, rule.TraversalInfo() };
      rightChildQueue.push(frr);
    }
  }

  // Now, recurse into the left and right children queues.  The order doesn't
  // matter.
  if (leftChildQueue.size() > 0)
    Traverse(*queryNode.Left(), leftChildQueue);
  if (rightChildQueue.size() > 0)
    Traverse(*queryNode.Right(), rightChildQueue);
}