37# include <gtest/gtest.h>
62 using Edge_Def = std::tuple<size_t, size_t, long long>;
74 for (
size_t i = 0; i <
nodes.size(); ++i)
88 for (
size_t i = 0; i < a.
size(); ++i)
98 const size_t min_size = std::min(a.
size(), b.
size());
99 for (
size_t i = 0; i < min_size; ++i)
111 bool canonical_less(
const Canonical_Path & a,
const Canonical_Path & b)
113 if (a.cost != b.cost)
114 return a.cost < b.cost;
121 for (
size_t i = 1; i < paths.
size(); ++i)
123 Canonical_Path key = paths[i];
127 paths[j] = paths[j - 1];
136 const Canonical_Path &
needle)
138 for (
size_t i = 0; i < paths.
size(); ++i)
149 for (
const auto & e :
init)
165 built.nodes.reserve(n);
166 for (
size_t i = 0; i < n; ++i)
167 built.nodes.append(
built.g.insert_node(
static_cast<int>(i)));
171 const auto & [u, v,
w] = it.get_curr();
184 ids.
append(it.get_current_node_ne()->get_info());
194 Node * node = it.get_current_node_ne();
195 if (
seen.contains(node))
203 template <
class Result_List>
207 for (
typename Result_List::Iterator it(
results); it.has_curr(); it.next_ne())
209 const auto & item = it.get_curr();
228 if (source == target)
232 p.nodes.append(source->get_info());
243 [&](
Node * u,
const long long cost)
249 for (
size_t i = 0; i < stack.
size(); ++i)
250 p.nodes.append(stack(i));
257 Arc * arc = it.get_current_arc_ne();
258 Node * v = it.get_tgt_node();
263 stack.
append(v->get_info());
264 dfs(v, cost + arc->get_info());
271 stack.
append(source->get_info());
277 while (
all.size() >
k)
286 std::bernoulli_distribution
has_edge(0.36);
287 std::uniform_int_distribution<int>
base_w(1, 40);
291 for (
size_t u = 0; u < n; ++u)
292 for (
size_t v = 0; v < n; ++v)
296 const long long w =
static_cast<long long>(
base_w(
rng))
297 +
static_cast<long long>(
edge_id * 101);
309 {0, 1, 1}, {0, 2, 1}, {1, 3, 1}, {2, 3, 1},
310 {1, 2, 1}, {2, 1, 1}, {0, 3, 5}
330 {0, 1, 1}, {0, 2, 1}, {1, 3, 1}, {2, 3, 1},
342 for (
size_t i = 0; i <
yen.size(); ++i)
352 {0, 1, 1}, {1, 2, 1}, {2, 3, 1},
377 {0, 1, 2}, {1, 2, 2}, {2, 0, 2}
396 {0, 1, 1}, {1, 0, 1}, {2, 3, 1}
409 {0, 1, 2}, {1, 2, -5}, {0, 2, 9}
424 std::mt19937_64
rng(0xBADC0FFEEULL);
425 std::uniform_int_distribution<int>
n_dist(3, 8);
429 const size_t n =
static_cast<size_t>(
n_dist(
rng));
433 constexpr size_t K = 7;
447 for (
size_t i = 0; i <
expected.size(); ++i)
450 <<
"trial=" <<
trial <<
", i=" << i;
452 <<
"trial=" <<
trial <<
", i=" << i;
457 <<
"trial=" <<
trial;
459 for (
size_t i = 1; i <
epp.size(); ++i)
462 <<
"trial=" <<
trial <<
", i=" << i;
471 {0, 1, 1}, {0, 2, 4}, {1, 2, 1}, {1, 3, 2},
472 {2, 3, 1}, {2, 4, 3}, {3, 4, 1}
479 long long prev = std::numeric_limits<long long>::min();
480 for (
auto it =
got.get_it(); it.has_curr(); it.next_ne())
482 const auto & item = it.get_curr();
485 prev = item.total_cost;
493 {0, 1, 1}, {1, 2, 1}, {2, 3, 1},
501 long long prev = std::numeric_limits<long long>::min();
502 for (
auto it =
got.get_it(); it.has_curr(); it.next_ne())
504 const auto & item = it.get_curr();
506 prev = item.total_cost;
591 const char *
env = std::getenv(
"PERF_TESTS_ENABLED");
592 if (
env ==
nullptr or std::string(
env) !=
"1")
593 GTEST_SKIP() <<
"Skipped: set PERF_TESTS_ENABLED=1 to run";
595 constexpr size_t N = 40;
596 constexpr size_t K = 25;
611 const auto t0 = std::chrono::steady_clock::now();
613 const auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(
614 std::chrono::steady_clock::now() -
t0).count();
617 <<
"yen_k_shortest_paths exceeded budget on trial " <<
trial
618 <<
": " << elapsed <<
" ms (budget " <<
BUDGET_MS <<
" ms,"
619 <<
" N=" <<
N <<
", K=" << K <<
", seed=" <<
MASTER_SEED <<
")";
624 long long prev = std::numeric_limits<long long>::min();
625 for (
auto it = result.get_it(); it.has_curr(); it.next_ne())
628 prev = it.get_curr().total_cost;
634 const auto t0 = std::chrono::steady_clock::now();
636 const auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(
637 std::chrono::steady_clock::now() -
t0).count();
640 <<
"eppstein_k_shortest_paths exceeded budget on trial " <<
trial
641 <<
": " << elapsed <<
" ms (budget " <<
BUDGET_MS <<
" ms,"
642 <<
" N=" <<
N <<
", K=" << K <<
", seed=" <<
MASTER_SEED <<
")";
646 long long prev = std::numeric_limits<long long>::min();
647 for (
auto it = result.get_it(); it.has_curr(); it.next_ne())
650 prev = it.get_curr().total_cost;
K-shortest path algorithms (Yen and Eppstein-style API).
WeightedDigraph::Node Node
bool has_curr() const noexcept
Check if there is a current valid item.
Simple dynamic array with automatic resizing and functional operations.
constexpr size_t size() const noexcept
Return the number of elements stored in the stack.
T & append(const T &data)
Append a copy of data
void reserve(size_t cap)
Reserves cap cells into the array.
Generic directed graph (digraph) wrapper template.
size_t size() const noexcept
Return the current dimension of array.
T pop()
Remove the last item of array (as if this was a stack)
T & append()
Allocate a new entry to the end of array.
void next_ne() noexcept
Advances the iterator to the next filtered element (noexcept version).
Arc Arc
The node class type.
Open addressing hash table with linear probing collision resolution.
constexpr bool contains(const Key &key) const noexcept
Alias for has().
void remove(const Key &key)
Remove the key referenced by key.
Iterator on nodes and arcs of a path.
bool has_current_node() const noexcept
Return true if the iterator has a current node.
Key * insert(const Key &key)
Inserts a key into the hash table (copy version).
DynArray< Graph::Node * > nodes
DFSResult< typename Domain::Distance > dfs(Domain &domain, typename Domain::State &state, SearchPath< typename Domain::Move > &path, const typename Domain::Distance g, const typename Domain::Distance threshold, const size_t depth, IDAStarResult< Solution, typename Domain::Distance > &result, OnSolution &on_solution)
Core recursive DFS used by IDA* for a single threshold pass.
Main namespace for Aleph-w library functions.
and
Check uniqueness with explicit hash + equality functors.
bool all(Container &container, Operation &operation)
Return true if all elements satisfy a predicate.
bool operator==(const DynList< T > &l1, const DynList< T > &l2)
Equality operator for DynList.
Divide_Conquer_DP_Result< Cost > divide_and_conquer_partition_dp(const size_t groups, const size_t n, Transition_Cost_Fn transition_cost, const Cost inf=dp_optimization_detail::default_inf< Cost >())
Optimize partition DP using divide-and-conquer optimization.
static std::atomic< bool > init
Iterator on the items of an array.
Arc of graph implemented with double-linked adjacency lists.
Filtered iterator of adjacent arcs of a node.
Dynamic array container with automatic resizing.
Lazy and scalable dynamic array implementation.
Generic graph and digraph implementations.
Open addressing hash table with linear probing.