PBeFS
Parallel Best-First Search
Loading...
Searching...
No Matches
MultiQueueBranchAndBound.h File Reference

Header file for MultiQueueBranchAndBound, the parallel Branch-and-Bound (B&B) whose workers share the open nodes in the MultiQueue of ADS, a relaxed priority queue of \( 2 p \) sequential queues each under its own lock, as the workers of MQAStar do. More...

#include <algorithm>
#include <atomic>
#include <cstdint>
#include <iterator>
#include <limits>
#include <memory>
#include <optional>
#include <utility>
#include <vector>
#include "PBeFS/bnb/ParallelBranchAndBound.h"
#include "ADS/concurrent/MultiQueue.h"

Go to the source code of this file.

Classes

class  MultiQueueBranchAndBound< P, Executor >
 the parallel B&B on the MultiQueue of ADS More...

Namespaces

namespace  PBeFS_di_unipi_it
 namespace for the Parallel Best-First Search library

Concepts

concept  PBeFS_di_unipi_it::MultiQueueValue
 the values that the MultiQueue of ADS takes as keys: arithmetic, with a greatest value, and atomic with no lock

Detailed Description

Header file for MultiQueueBranchAndBound, the parallel Branch-and-Bound (B&B) whose workers share the open nodes in the MultiQueue of ADS, a relaxed priority queue of \( 2 p \) sequential queues each under its own lock, as the workers of MQAStar do.

The problem, the options and the Solution are those of BranchAndBound.h and ParallelBranchAndBound.h, and the design is discussed in docs/branch-and-bound.md.

The search is that of SharedBranchAndBound [see ParallelBranchAndBound.h] but for the queue and the test of the end: a pop takes the better of the first nodes of two queues drawn at random, and therefore not always the first of all, and the counter \( m \) of the nodes that are in the queue or held by a worker, which is atomic, takes the place of busy and of the lock \( L \):

1 procedure MULTIQUEUE(R)
2 Q ← R; m ← |R|; done ← false
3 in parallel, on each worker i = 0, ..., p − 1 do
4 d ← nil
5 while not done do
6 if d ≠ nil then n ← d; d ← nil
7 else
8 n ← a pop of Q, possibly nothing
9 if no node was popped then
10 if m = 0 then done ← true else wait a little
11 continue
12 if PRUNABLE(the bound of n) then
13 n is a leaf (pruned); m ← m − 1; continue
14 if a limit is reached then n is a leaf (open); done ← true
15 K ← PROCESS(n); d ← DIVE(K)
16 m ← m + |K| − 1; push the nodes of K but d in one queue of Q

The test at line 10 is exact: at line 16, \( m \) counts the children and drops the node processed in one atomic step, before the pushes (the child that dives is held by the worker, and counted as such), so that \( m = 0 \) means that \( Q \) is empty and that no worker holds a node, whatever the order of the pops. Since the first node of \( Q \) is not known, a node is pruned when popped (line 12) rather than with all the others, and DIVE compares the children with the bound of the node processed instead of the least bound of \( Q \). The children of a node go into one queue under one lock, as by a stickiness of their number.

Author
Donato Meoli
Dipartimento di Informatica
Università di Pisa