49# ifndef STATE_SEARCH_COMMON_H
50# define STATE_SEARCH_COMMON_H
102template <SearchMove Move>
109 return std::chrono::duration<double, std::milli>(duration).count();
119template <
typename Key,
131template <
typename Key,
145template <
typename Set,
typename Key>
147 { set.contains(key) } -> std::convertible_to<bool>;
165template <
typename Map,
typename Key,
typename Objective>
167 map.insert(key,
obj);
169 { map.search(key) ==
nullptr } -> std::convertible_to<bool>;
170 map.search(key)->second =
obj;
193template <
typename Domain>
196 const typename Domain::State &state,
197 const typename Domain::Move &move) {
198 { domain.bound_after(state, move) }
199 -> std::convertible_to<typename Domain::Objective>;
218template <
typename Domain>
221 const typename Domain::State &state,
222 const typename Domain::Move &move) {
223 { domain.evaluate_after(state, move) }
224 -> std::convertible_to<typename Domain::Score>;
245template <
typename Engine>
279template <SearchMove Move>
328template <SearchState State, SearchMove Move>
343template <
typename Solution>
346 bool operator()(
const Solution &,
const Solution &)
const noexcept
360 template <
typename Solution>
372template <
typename Visitor,
typename Solution>
374 {
visitor(solution) } -> std::convertible_to<bool>;
385template <
typename Solution>
403 <<
"SearchSolutionCollector: max_solutions must be positive";
459template <
typename Solution,
typename Compare = KeepFirstSolution<Solution>>
498 <<
"BestSolution::get: no incumbent solution available";
508 <<
"BestSolution::get: no incumbent solution available";
552template <
typename Solution,
typename Compare = KeepFirstSolution<Solution>>
563template <
typename Domain>
565 typename Domain::State;
566 typename Domain::Move;
570 d.for_each_successor(state,
571 [](
const typename Domain::Move &) ->
bool
575 } -> std::convertible_to<bool>;
593template <
typename Domain>
595 { d.is_goal(state) } -> std::convertible_to<bool>;
599template <
typename Domain>
601 { d.is_terminal(state) } -> std::convertible_to<bool>;
610template <
typename Domain>
612 { d.should_prune(state, depth) } -> std::convertible_to<bool>;
616template <
typename Domain>
618 typename Domain::Move_Key;
619 { d.move_key(move) } -> std::convertible_to<typename Domain::Move_Key>;
626template <
typename Prov
ider>
628 typename Provider::State_Key;
629 {
provider.state_key(state) } -> std::convertible_to<typename Provider::State_Key>;
638template <
typename Domain>
640 typename Domain::Distance;
641 { d.heuristic(state) } -> std::convertible_to<typename Domain::Distance>;
649template <
typename Domain>
651 =
requires(
Domain &d,
const typename Domain::State &state,
const typename Domain::Move &move) {
652 typename Domain::Distance;
653 { d.cost(state, move) } -> std::convertible_to<typename Domain::Distance>;
667template <
typename Domain>
670and requires(
Domain &d,
typename Domain::State &state,
const typename Domain::Move &move) {
671 { d.apply(state, move) } -> std::same_as<void>;
672 { d.undo(state, move) } -> std::same_as<void>;
680template <
typename Solution,
typename Compare = KeepFirstSolution<Solution>>
740namespace search_engine_detail {
752template <
typename Domain>
754 const typename Domain::State &state)
757 return domain.is_terminal(state);
773template <
typename Domain>
775 const typename Domain::State &state,
779 return domain.should_prune(state, depth);
792template <
typename Result>
795 ++result.stats.visited_states;
796 if (depth > result.stats.max_depth_reached)
797 result.stats.max_depth_reached = depth;
812template <
typename Result>
817 ++result.stats.limit_hits;
845template <
typename Result>
853 ++result.stats.limit_hits;
C++20 concepts hub: comparison, BST policy, and Aleph container concepts.
Exception handling system with formatted messages for Aleph-w.
#define ah_runtime_error_unless(C)
Throws std::runtime_error if condition does NOT hold.
#define ah_invalid_argument_if(C)
Throws std::invalid_argument if condition holds.
void reserve(size_t cap)
Reserves cap cells into the array.
Tracks the best solution seen so far according to a comparator.
bool has_value() const noexcept
Return true if an incumbent exists.
Solution & get()
Mutable access to the current incumbent.
std::optional< Solution > current_
Compare Compare_Type
Type of the comparison policy.
bool consider(Solution &&candidate)
Consider a candidate by move.
const Compare & compare() const noexcept
Access the ordering functor used by this incumbent.
void clear() noexcept
Remove the stored incumbent, if any.
BestSolution(Compare compare)
Build a tracker with a custom comparator.
bool consider(const Solution &candidate)
Consider a candidate by copy.
BestSolution()=default
Build an empty incumbent tracker.
const Solution & get() const
Read the current incumbent.
Solution Solution_Type
Type of stored solutions.
T & append(const T &item)
void empty() noexcept
empty the list
Open addressing hash table with linear probing collision resolution.
Collector that stores accepted solutions in an Aleph list.
bool operator()(const Solution &solution)
Append one solution and report whether enumeration should continue.
Container_Type & solutions() noexcept
Mutable access to the collected solutions.
size_t size() const noexcept
Number of collected solutions.
const Container_Type & solutions() const noexcept
Access the collected solutions.
bool is_empty() const noexcept
Return true if no solution has been collected.
SearchSolutionCollector(const size_t max_solutions)
Build a collector that stops after max_solutions.
void clear() noexcept
Remove all collected solutions.
Solution Solution_Type
Type of collected solutions.
SearchSolutionCollector()=default
Build a collector with no limit.
Container_Type solutions_
Concept for domains that provide the cost of applying a move.
An element type the Aleph arrays can store.
Minimal contract for DFS/backtracking domains.
A callable that takes two const T& and returns bool.
Optional concept for domain-side pruning hooks.
Concept for domains that can recognize goal states.
Concept for domains that provide an admissible heuristic.
Concept for domains that can estimate a move's bound without modifying state (incremental bound for B...
Concept for adversarial-search domains that can estimate a child score without modifying state (incre...
Optional concept for domains that can key moves for history heuristics.
Minimal requirement for search moves.
Concept for callbacks invoked on each accepted solution.
Generic concept for domains that can expose a stable state key.
Minimal requirement for mutable search states.
Concept for lazy successor generation.
Concept that checks whether a search engine supports the Best_First exploration strategy at compile t...
Optional concept for explicit non-solution terminal states.
Concept for a map tracking the best bound seen per visited state.
Concept for a set suitable for tracking globally visited states.
size_t blossom_maximum_cardinality_matching(const GT &g, DynDlist< typename GT::Arc * > &matching, SA sa=SA())
Alias of compute_maximum_cardinality_general_matching().
Singly linked list implementations with head-tail access.
bool should_prune_state(Domain &domain, const typename Domain::State &state, const size_t depth)
Dispatch helper for the optional should_prune hook.
bool is_terminal_state(const Domain &domain, const typename Domain::State &state)
Dispatch helper for the optional is_terminal hook.
bool stop_after_solution(Result &result, const ExplorationPolicy &policy, const SearchLimits &limits)
Decide whether to stop the search after a solution was accepted.
void register_visit(const size_t depth, Result &result)
Update visit counters and max-depth statistic.
bool expansion_limit_reached(Result &result, const SearchLimits &limits)
Check whether the expansion limit has been reached.
Main namespace for Aleph-w library functions.
std::chrono::steady_clock SearchClock
Monotonic clock used for search timings.
constexpr size_t Search_Unlimited
Sentinel used by SearchLimits to mean "no bound".
SearchStatus
Final state of a search execution.
@ LimitReached
Search stopped because an external hard limit was hit.
@ Exhausted
Search space within the configured bounds was exhausted.
@ StoppedOnSolution
Search stopped because solution handling requested it.
@ NotStarted
Search object exists but no traversal has run yet.
void reserve_search_path(SearchPath< Move > &path, const SearchLimits &limits)
and
Check uniqueness with explicit hash + equality functors.
double search_elapsed_ms(const SearchClock::duration &duration) noexcept
MoveOrderingMode
Built-in move-ordering modes supported by the framework.
@ Domain
Preserve the order emitted by for_each_successor().
Shared support for configurable successor ordering heuristics.
Default solution visitor that always continues the search.
bool operator()(const Solution &) const noexcept
Accepts any solution and returns true.
Exploration controls shared across engines.
bool stop_at_first_solution
Stop when the first goal is found.
Strategy strategy
Traversal strategy.
MoveOrderingMode move_ordering
Successor-ordering mode.
Strategy
Traversal strategy supported by the engine.
@ Best_First
Priority-guided expansion; only supported by Branch_And_Bound.
@ Depth_First
Recursive depth-first traversal (all engines).
bool use_history_heuristic
Enable experimental history heuristic where supported.
bool use_killer_moves
Enable experimental killer heuristic where supported.
Comparison policy that keeps the first solution seen.
bool operator()(const Solution &, const Solution &) const noexcept
Open addressing hash map using linear probing.
Statistics collected by engines that reorder successor batches.
Hard bounds applied by the search engine.
size_t max_expansions
Maximum expanded states.
size_t max_solutions
Maximum accepted solutions.
size_t max_depth
Maximum expansion depth.
Aggregates the outcome of one search execution.
bool limit_reached() const noexcept
Return true if a hard search limit stopped the traversal.
SearchStats stats
Statistics collected during the run.
bool found_solution() const noexcept
Return true if at least one solution was retained.
bool stopped_on_solution() const noexcept
Return true if search stopped because solution handling requested it.
ExplorationPolicy policy
Exploration policy used for the run.
Solution Solution_Type
Type of solutions in this result.
SearchResult()=default
Build an empty result.
Compare Compare_Type
Type of the comparison policy.
bool exhausted() const noexcept
Return true if the search exhausted the configured region.
SearchLimits limits
Limits used for the run.
SearchStatus status
Final execution state.
Incumbent_Type best_solution
Best incumbent retained by the engine.
SearchResult(Compare compare)
Build a result with a specific solution comparator.
Snapshot of a concrete solution encountered during the traversal.
SearchPath< Move > path
Move sequence leading to state.
State state
Snapshot of the terminal state.
size_t depth
Path depth of the solution.
Counters collected during a search run.
size_t limit_hits
Number of hard-limit stops triggered.
size_t pruned_by_visited
States skipped because already seen (visited-set duplicate suppression).
size_t pruned_by_domain
States discarded by domain-side pruning.
size_t terminal_states
Non-solution terminal states cut by the domain.
double elapsed_ms
Wall-clock time spent inside the search call.
MoveOrderingStats move_ordering
Successor-ordering activity for this run.
size_t pruned_by_depth
States not expanded due to max depth.
size_t generated_successors
Number of successor moves emitted.
size_t max_depth_reached
Deepest path depth visited.
size_t solutions_found
Number of goal states accepted.
size_t expanded_states
Number of non-terminal states expanded.
size_t visited_states
Number of states entered by the engine.
Dynamic array container with automatic resizing.
Unified hash table interface.