37# include <gtest/gtest.h>
60 using Edge_Def = std::tuple<size_t, size_t, long long>;
68 std::vector<typename GT::Node *>
nodes;
69 std::vector<typename GT::Arc *>
arcs;
76 template <
class GT,
typename Weight_Type>
78 build_graph_generic(
const size_t n,
const std::vector<std::tuple<size_t, size_t, Weight_Type>> & edges)
81 built.nodes.reserve(n);
82 built.arcs.reserve(edges.size());
84 for (
size_t i = 0; i < n; ++i)
85 built.nodes.push_back(
built.g.insert_node(
static_cast<int>(i)));
87 for (
const auto & [u, v,
w] : edges)
94 Built_Graph
build_graph(
const size_t n,
const std::vector<Edge_Def> & edges)
110 struct Exact_Oracle_Result
113 long double minimum_mean = std::numeric_limits<long double>::infinity();
119 const size_t n =
built.nodes.size();
121 Exact_Oracle_Result
oracle;
122 std::vector<bool> visited(n,
false);
124 std::function<
void(
size_t,
size_t,
long long,
size_t)>
dfs =
125 [&](
const size_t start,
127 const long long cost,
132 Arc * arc = it.get_current_arc_ne();
133 const size_t v =
static_cast<size_t>(it.get_tgt_node()->get_info());
134 const long long w = arc->get_info();
138 const size_t cyc_len = len + 1;
139 const long double mean =
static_cast<long double>(cost +
w)
140 /
static_cast<long double>(
cyc_len);
142 if (mean <
oracle.minimum_mean)
151 dfs(start, v, cost +
w, len + 1);
156 for (
size_t s = 0; s < n; ++s)
169 if (
r.cycle_length == 0)
170 return r.cycle_nodes.is_empty()
and r.cycle_arcs.is_empty();
172 if (
r.cycle_nodes.size() !=
r.cycle_length + 1)
174 if (
r.cycle_arcs.size() !=
r.cycle_length)
177 auto node_it =
r.cycle_nodes.get_it();
206 Arc * blocked =
nullptr;
208 bool operator()(
Arc * arc)
const noexcept
210 return arc != blocked;
230 const std::vector<Edge_Def> edges = {
231 {0, 1, 2}, {1, 2, 3}, {2, 3, 4}, {0, 3, 10}
244 const std::vector<Edge_Def> edges = {
245 {0, 1, 8}, {1, 1, 3}, {1, 2, 7}, {2, 0, 9}
252 EXPECT_NEAR(
static_cast<double>(
r.minimum_mean), 3.0, 1e-12);
262 const std::vector<Edge_Def> edges = {
263 {0, 1, 3}, {1, 0, 1},
264 {1, 2, 1}, {2, 1, 1},
272 EXPECT_NEAR(
static_cast<double>(
r.minimum_mean), 1.0, 1e-12);
279 const std::vector<Edge_Def> edges = {
280 {0, 1, -5}, {1, 2, 1}, {2, 0, 1},
288 EXPECT_NEAR(
static_cast<double>(
r.minimum_mean), -1.0, 1e-12);
295 const std::vector<Edge_Def> edges = {
296 {0, 1, 1}, {1, 0, 1},
304 EXPECT_NEAR(
static_cast<double>(full.minimum_mean), 1.0, 1e-12);
317 const std::vector<Float_Edge_Def> edges = {
318 {0, 1, 0.5}, {1, 0, 1.0},
319 {1, 2, 2.5}, {2, 1, 2.5}
329 EXPECT_NEAR(
static_cast<double>(full.minimum_mean), 0.75, 1e-12);
332 EXPECT_NEAR(
static_cast<double>(value.minimum_mean), 0.75, 1e-12);
346 inf_graph.insert_arc(
i0,
i1, std::numeric_limits<double>::infinity());
355 nan_graph.insert_arc(n0, n1, std::numeric_limits<double>::quiet_NaN());
364 const std::vector<Edge_Def> edges = {
365 {0, 1, std::numeric_limits<long long>::max()},
376 const std::vector<Edge_Def> edges = {
377 {0, 1, 3}, {1, 2, 3}, {2, 0, 0},
386 EXPECT_NEAR(
static_cast<double>(
r.minimum_mean), 2.0, 1e-12);
388 EXPECT_NEAR(
static_cast<double>(v.minimum_mean), 2.0, 1e-12);
394 const std::vector<Edge_Def> edges = {
395 {0, 1, 2}, {1, 0, 2},
432 std::mt19937_64
rng(0xDA7A5EEDULL);
433 std::uniform_int_distribution<int>
n_dist(2, 7);
434 std::bernoulli_distribution
has_edge(0.36);
435 std::uniform_int_distribution<int>
weight_dist(-9, 13);
439 const size_t n =
static_cast<size_t>(
n_dist(
rng));
440 std::vector<Edge_Def> edges;
441 for (
size_t u = 0; u < n; ++u)
442 for (
size_t v = 0; v < n; ++v)
446 if (std::bernoulli_distribution(0.12)(
rng))
447 edges.emplace_back(u, v,
static_cast<long long>(
weight_dist(
rng)));
452 edges.emplace_back(u, v,
static_cast<long long>(
weight_dist(
rng)));
466 static_cast<double>(
exact.minimum_mean),
468 <<
"trial=" <<
trial;
470 static_cast<double>(
exact.minimum_mean),
472 <<
"trial=" <<
trial;
477 const long double witness_mean =
static_cast<long double>(
got.cycle_total_cost)
478 /
static_cast<long double>(
got.cycle_length);
Minimum mean cycle in directed graphs (Karp algorithm).
WeightedDigraph::Node Node
Generic directed graph (digraph) wrapper template.
void next_ne() noexcept
Advances the iterator to the next filtered element (noexcept version).
virtual Node * insert_node(Node *node) noexcept
Insertion of a node already allocated.
Arc Arc
The node class type.
Arc * insert_arc(Node *src_node, Node *tgt_node, void *a)
Node * get_src_node(Arc *arc) const noexcept
Return the source node of arc (only for directed graphs)
Node * get_tgt_node(Arc *arc) const noexcept
Return the target node of arc (only for directed graphs)
DynArray< Graph::Node * > nodes
DynArray< Graph::Arc * > arcs
Min_Mean_Cycle_Value_Result minimum_mean_cycle_value(const GT &g, Distance distance=Distance(), SA sa=SA())
Alias for karp_minimum_mean_cycle_value().
bool has_cycle(const GT &g)
Return true if an undirected graph has at least one cycle.
Min_Mean_Cycle_Result< GT, typename Distance::Distance_Type > minimum_mean_cycle(const GT &g, Distance distance=Distance(), SA sa=SA())
Alias for karp_minimum_mean_cycle().
Min_Mean_Cycle_Value_Result karp_minimum_mean_cycle_value(const GT &g, Distance distance=Distance(), SA sa=SA())
Compute only the minimum mean value (without witness walk).
Min_Mean_Cycle_Result< GT, typename Distance::Distance_Type > karp_minimum_mean_cycle(const GT &g, Distance distance=Distance(), SA sa=SA())
Compute minimum mean cycle by Karp's algorithm.
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.
Container2< typename Container1::Item_Type > filter(Container1 &container, Operation &operation)
Filter elements that satisfy operation.
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.
auto mean(const Container &data) -> std::decay_t< decltype(*std::begin(data))>
Compute the arithmetic mean.
void next()
Advance all underlying iterators (bounds-checked).
Arc of graph implemented with double-linked adjacency lists.
Result of minimum mean cycle computation.
Filtered iterator of adjacent arcs of a node.
Array-based graph implementation.
Generic graph and digraph implementations.