The algorithms
We start from the sequential search (astar( d ) in AStar.h), which is A*
with the goal test at the expansion and a node reopened when a cheaper path
to it is found. Ties on f are broken in favour of the larger g, which on
domains with many states in the last f layer usually reaches the goal much
earlier. Next to it, idastar( d ) (IDAStar.h) is the iterative-deepening
A* of Korf [7], a depth-first search bounded by f and repeated with
a growing bound, which keeps only the current path and hence solves the
problems whose CLOSED would not fit in memory, such as the 24-puzzle, at the
price of expanding again the states reached by more than one path. Between
the two, ddd_astar( d ) (DDDAStar.h) keeps OPEN and CLOSED in files on
the disk, in buckets of equal g and h split by the hash of the state, which
it expands by increasing f and then g, the duplicates of each file being
removed in memory against the closed files of the same h, as in the
External A* of Edelkamp, Jabbar and Schrödl [39] with the
hash-based delayed duplicate detection of Korf [40]; its memory
is that of the largest file of a bucket rather than that of all the states,
at the price of the time of the disk, and it needs integer costs, a
consistent heuristic and states that are trivially copyable. The
parallel searches are the following, each one with the
reference for its correctness and its typical behavior.
SPAStar(SPAStar.h) is the Simple Parallel A* of Algorithm 2 of [1], in which the workers share one OPEN and one CLOSED list, protected by locks. It is the baseline of the survey, and it is not expected to scale beyond a few threads, since each expansion goes through the shared lists.MQAStar(MQAStar.h) is SPA* with a relaxed OPEN list, the MultiQueue of [37] from ADS: \(2p\) queues under a lock each, a node pushed into one drawn at random and popped from the better of two, so that the workers rarely wait for one another, at the price of expanding nodes a little out of the order of f; the search ends when a counter of the nodes in OPEN or being expanded falls to 0.HDAStar(HDAStar.h) is Hash Distributed A* [2]: a distribution function assigns each state to a worker, which keeps OPEN and CLOSED for the states it owns and receives, packed in batches, those generated by the others. The search ends when no worker has a node with f smaller than the incumbent and no batch is travelling. The distribution is a template parameter (Distribution.h), and the library provides those compared by Jinnai and Fukunaga [5], i.e., Zobrist hashing (HDA*[Z]), Abstract Zobrist hashing (AZHDA*), Zobrist hashing of an abstract state (AHDA* [3]) and the perfect hash modulo the number of workers (HDA*[P], the “bad” case of [3]). Furthermore, it provides the hash of the closed list and, as the baseline without duplicate detection across workers, a random assignment.HDAStarMPI(HDAStarMPI.h) is the same search with one MPI process per worker, a nonblocking exchange of the batches and the termination detection of Mattern [11] (four counters reduced withMPI_Iallreduce). At the end, the path is rebuilt state by state, each one sent by the process that holds it.SafePBNF(SafePBNF.h) is the livelock-free Parallel Best-NBlock-First search of Burns et al. [3], in which an abstraction partitions the state space into nblocks. A worker expands for a while the nodes of an nblock whose duplicate detection scope (its abstract successors) is not in use by another worker; hence, no lock is taken on the single node.PASE(PASE.h) is the Parallel A* for Slow Expansions of Phillips et al. [6], which expands in parallel only the states that the pairwise heuristic proves not to be reachable through a cheaper path from a state still in OPEN. It may pay off only when an expansion costs much more than the bookkeeping;SlowDomain.hadds a given amount of artificial work per expansion to study this regime.FarmAStar(FarmAStar.h) is a centralized parallel A* written as a farm with feedback, i.e., the master-worker scheme of [1]: a master holds OPEN and CLOSED, and the workers generate the successors of the nodes it sends them.
The shared-memory searches are templates also over the executor of
ADS that runs the workers, i.e., its pool
of C++ threads (ADS::ThreadPool, the default), ADS::OpenMPExecutor or
ADS::FastFlowExecutor, and they take their channels, the mailbox that
detects the end of HDA* and of the distributed B&B, and the farm with
feedback from ADS as well (on FastFlow the farm is a farm of FastFlow, and
the channels a mesh of single-producer single-consumer queues); a caller
that runs many searches may give them an executor of its own by
set_executor(), which saves the start of the threads at each search.
Their options are in ParallelOptions: the number of workers, the size of
a batch, the number of expansions between two flushes of a partially
filled batch and the seed of the distribution.