38#include <gtest/gtest.h>
58class NetCostArcTest :
public ::testing::Test
149class NetCostGraphTest :
public ::testing::Test
163 auto n = net.insert_node();
170 auto s = net.insert_node();
171 auto t = net.insert_node();
172 auto arc = net.insert_arc(s, t, 10.0, 2.5);
182 auto s = net.insert_node();
183 auto t = net.insert_node();
184 auto arc = net.insert_arc(s, t, 10.0, 5.0);
186 net.get_cost(arc) = 7.5;
192 auto s = net.insert_node();
193 auto t = net.insert_node();
194 auto arc = net.insert_arc(s, t, 10.0, 3.0);
202 auto s = net.insert_node();
203 auto t = net.insert_node();
204 auto arc = net.insert_arc(s, t, 10.0, 2.0);
212 auto s = net.insert_node();
213 auto a = net.insert_node();
214 auto t = net.insert_node();
216 auto arc1 = net.insert_arc(s, a, 10.0, 2.0);
217 auto arc2 = net.insert_arc(a, t, 10.0, 3.0);
236class NetCostGraphCopyTest :
public ::testing::Test
243 void SetUp()
override
296class ResidualNetTest :
public ::testing::Test
305 auto s =
rnet.insert_node();
306 auto t =
rnet.insert_node();
330 auto s =
rnet.insert_node();
331 auto t =
rnet.insert_node();
344class FilterTest :
public ::testing::Test
391 EXPECT_EQ(arc->cap, std::numeric_limits<double>::max());
401class FlowParsTest :
public ::testing::Test
407 void SetUp()
override
423 auto [cap, flow, cost] = net.out_pars(s);
437 auto [cap, flow, cost] = net.in_pars(t);
446 auto [cap, flow, cost] = net.out_pars(s);
522class FeasibleTreeTest :
public ::testing::Test
573class MaxFlowMinCostIntegrationTest :
public ::testing::Test
699 Net build_diamond_network()
721 flow += it.get_curr()->flow;
731 for (
auto p : net.
nodes())
733 if (p == source || p == sink)
736 double in_flow = 0, out_flow = 0;
739 in_flow += it.get_curr()->flow;
742 out_flow += it.get_curr()->flow;
744 if (std::abs(in_flow - out_flow) > 1e-9)
753 for (
auto a : net.
arcs())
755 if (a->flow < 0 || a->flow > a->cap)
769 double total_cost = net.flow_cost();
784 double total_cost = net.flow_cost();
796 auto net = build_diamond_network();
801 double total_cost = net.flow_cost();
822 double total_cost = net.flow_cost();
839 std::cout <<
"Textbook network: max_flow=" << max_flow
840 <<
", total_cost=" << total_cost
841 <<
", cycles_cancelled=" << cycles << std::endl;
884 double total_cost = net.flow_cost();
891 std::cout <<
"Larger network: max_flow=" << max_flow
892 <<
", total_cost=" << total_cost
893 <<
", cycles_cancelled=" << cycles << std::endl;
904 double total_cost = net.flow_cost();
914class NetworkSimplexTest :
public ::testing::Test
949 Net build_diamond_network()
1011 flow += it.get_curr()->flow;
1020 for (
auto p : net.
nodes())
1022 if (p == source || p == sink)
1025 double in_flow = 0, out_flow = 0;
1028 in_flow += it.get_curr()->flow;
1031 out_flow += it.get_curr()->flow;
1033 if (std::abs(in_flow - out_flow) > 1e-9)
1041 for (
auto a : net.
arcs())
1043 if (a->flow < 0 || a->flow > a->cap + 1e-9)
1057 double total_cost = net.flow_cost();
1072 double total_cost = net.flow_cost();
1082 auto net = build_diamond_network();
1087 double total_cost = net.flow_cost();
1102 double total_cost = net.flow_cost();
1110 std::cout <<
"Network Simplex textbook: max_flow=" << max_flow
1111 <<
", total_cost=" << total_cost
1112 <<
", pivots=" << pivots << std::endl;
1122 double total_cost = net.flow_cost();
1129 std::cout <<
"Network Simplex larger: max_flow=" << max_flow
1130 <<
", total_cost=" << total_cost
1131 <<
", pivots=" << pivots << std::endl;
1142 double total_cost = net.flow_cost();
1191 double total_cost = net.flow_cost();
1220 double total_cost = net.flow_cost();
1233class SimplexDataStructuresTest :
public ::testing::Test
1250 EXPECT_NE(
static_cast<int>(Simplex_Arc_State::Lower),
1251 static_cast<int>(Simplex_Arc_State::Upper));
1252 EXPECT_NE(
static_cast<int>(Simplex_Arc_State::Lower),
1253 static_cast<int>(Simplex_Arc_State::Tree));
1254 EXPECT_NE(
static_cast<int>(Simplex_Arc_State::Upper),
1255 static_cast<int>(Simplex_Arc_State::Tree));
1295class NetworkSimplexVsPureSimplexTest :
public ::testing::Test
1323 std::vector<ArcData>
arcs = {
1331 static constexpr int SOURCE = 0;
1332 static constexpr int SINK = 3;
1333 static constexpr int NUM_NODES = 4;
1338 std::vector<Node*>
nodes(NUM_NODES);
1340 for (
int i = 0; i < NUM_NODES; ++i)
1343 for (
const auto& a :
arcs)
1344 net.insert_arc(
nodes[a.src],
nodes[a.tgt], a.cap, a.cost);
1369 const size_t NUM_ARCS =
arcs.size();
1370 const size_t NUM_VARS = NUM_ARCS + 1;
1371 const double M = 1000.0;
1373 auto start = std::chrono::high_resolution_clock::now();
1379 for (
size_t i = 0; i < NUM_ARCS; ++i)
1380 simplex.put_objetive_function_coef(i, -arcs[i].cost);
1381 simplex.put_objetive_function_coef(NUM_ARCS, M);
1385 return std::vector<double>(
NUM_VARS + 1, 0.0);
1389 for (
size_t i = 0; i < NUM_ARCS; ++i)
1447 coefs[NUM_ARCS] = -1.0;
1454 coefs[NUM_ARCS] = 1.0;
1461 simplex.prepare_linear_program();
1464 auto end = std::chrono::high_resolution_clock::now();
1465 double time_ms = std::chrono::duration<double, std::milli>(end - start).count();
1472 double max_flow =
simplex.get_solution(NUM_ARCS);
1473 double total_cost = 0;
1474 for (
size_t i = 0; i < NUM_ARCS; ++i)
1475 total_cost +=
simplex.get_solution(i) *
arcs[i].cost;
1477 return {max_flow, total_cost,
time_ms};
1486 auto start = std::chrono::high_resolution_clock::now();
1488 auto end = std::chrono::high_resolution_clock::now();
1490 double time_ms = std::chrono::duration<double, std::milli>(end - start).count();
1493 double max_flow = 0;
1496 max_flow += it.get_curr()->flow;
1498 return {max_flow, net.flow_cost(),
time_ms};
1507 std::cout <<
"\n=== Network Simplex vs Pure Simplex Validation ===\n";
1517 <<
"Max flow differs between methods";
1519 <<
"Min cost differs between methods";
1521 std::cout <<
"✓ Both methods produce identical optimal solution\n";
1527 const int RUNS = 10;
1531 for (
int i = 0; i <
RUNS; ++i)
1543 std::cout <<
"\n=== Performance Comparison (" <<
RUNS <<
" runs) ===\n";
1544 std::cout <<
"Avg Pure Simplex time: " <<
avg_simplex <<
" ms\n";
1545 std::cout <<
"Avg Network Simplex time: " <<
avg_network <<
" ms\n";
1557class LargeNetworkValidationTest :
public ::testing::Test
1564 std::vector<std::vector<Node*>>
nodes(n, std::vector<Node*>(n));
1567 for (
int i = 0; i < n; ++i)
1568 for (
int j = 0; j < n; ++j)
1572 for (
int i = 0; i < n; ++i)
1574 for (
int j = 0; j < n; ++j)
1579 double cap = 10.0 + (i + j) % 5;
1580 double cost = 1.0 + (i * j) % 3;
1586 double cap = 10.0 + (i + j + 1) % 5;
1587 double cost = 1.0 + ((i + 1) * j) % 3;
1599 const int GRID_SIZE = 5;
1610 auto start_ns = std::chrono::high_resolution_clock::now();
1612 auto end_ns = std::chrono::high_resolution_clock::now();
1616 auto start_cc = std::chrono::high_resolution_clock::now();
1618 auto end_cc = std::chrono::high_resolution_clock::now();
1622 auto get_flow = [](
const Net& net) {
1626 flow += it.get_curr()->flow;
1635 std::cout <<
"\n=== Grid Network " << GRID_SIZE <<
"x" << GRID_SIZE
1636 <<
" (" <<
net1.vsize() <<
" nodes, " <<
net1.esize() <<
" arcs) ===\n";
1637 std::cout <<
"Ford-Fulkerson only: cost=" <<
cost_after_ff <<
"\n";
1638 std::cout <<
"Network Simplex: flow=" <<
flow_ns <<
", cost=" <<
cost_ns
1640 std::cout <<
"Cycle Canceling: flow=" <<
flow_cc <<
", cost=" <<
cost_cc
1649 std::cout <<
"\n⚠ BUG DETECTED: Cost difference = " << std::abs(
cost_ns -
cost_cc) <<
"\n";
1653 std::cout <<
" Network Simplex found SUBOPTIMAL solution (pivots=" <<
pivots_ns <<
")\n";
1654 std::cout <<
" Cost after Ford-Fulkerson: " <<
cost_after_ff <<
"\n";
1655 std::cout <<
" Cost after Network Simplex: " <<
cost_ns <<
"\n";
1657 std::cout <<
" Cost after Cycle Canceling: " <<
cost_cc <<
"\n";
1659 std::cout <<
" => Network Simplex is NOT optimizing correctly!\n";
1663 std::cout <<
" Cycle Canceling found higher cost (unexpected).\n";
1668 std::cout <<
"✓ Both algorithms produce identical optimal solution\n";
1680 const int GRID_SIZE = 5;
1685 std::cout <<
"\n=== Phase I Diagnostic ===\n";
1691 for (
auto a : net.
arcs())
1692 if (a->flow > 1e-9
and a->flow < a->cap - 1e-9)
1695 std::cout <<
"Partial arcs after FF: " <<
partial_before <<
"\n";
1698 size_t pivots =
simplex.run();
1702 size_t remaining =
simplex.count_non_tree_partial_arcs();
1704 std::cout <<
"Pivots performed: " << pivots <<
"\n";
1705 std::cout <<
"Valid BFS: " << (
valid_bfs ?
"YES" :
"NO") <<
"\n";
1706 std::cout <<
"Partial arcs not in tree: " << remaining <<
"\n";
1707 std::cout <<
"Final cost: " << net.flow_cost() <<
"\n";
1715 std::cout <<
"Optimal cost (CC): " <<
net2.flow_cost() <<
"\n";
1718 std::cout <<
"WARNING: Phase I failed to establish valid BFS!\n";
1721 std::cout <<
"WARNING: " << remaining <<
" partial arcs still outside tree!\n";
1724 std::cout <<
"\nNon-tree arc analysis:\n";
1725 for (
auto a : net.
arcs())
1730 bool at_upper = (a->flow >= a->cap - 1e-9);
1749 auto [
cycle, iterations] =
BF(
rnet).search_negative_cycle(0.4, 10);
1753 std::cout <<
"NEGATIVE CYCLE FOUND after Network Simplex!\n";
1754 std::cout <<
" Cycle has " <<
cycle.
size() <<
" arcs\n";
1757 std::cout <<
" Cycle cost: " <<
cycle_cost <<
"\n";
1760 std::cout <<
"No negative cycles found - this is strange!\n";
1766 std::cout <<
"\n=== Performance Comparison ===\n";
1767 std::cout << std::setw(8) <<
"Grid" << std::setw(10) <<
"Nodes"
1768 << std::setw(10) <<
"Arcs" << std::setw(12) <<
"NS (ms)"
1769 << std::setw(12) <<
"CC (ms)" << std::setw(10) <<
"Winner\n";
1770 std::cout << std::string(62,
'-') <<
"\n";
1777 auto start1 = std::chrono::high_resolution_clock::now();
1779 auto end1 = std::chrono::high_resolution_clock::now();
1780 double time_ns = std::chrono::duration<double, std::milli>(
end1 -
start1).count();
1782 auto start2 = std::chrono::high_resolution_clock::now();
1784 auto end2 = std::chrono::high_resolution_clock::now();
1785 double time_cc = std::chrono::duration<double, std::milli>(
end2 -
start2).count();
1789 <<
"Different costs for grid " <<
size <<
"x" <<
size;
1791 std::cout << std::setw(5) <<
size <<
"x" <<
size
1792 << std::setw(10) <<
net1.vsize()
1793 << std::setw(10) <<
net1.esize()
1794 << std::setw(12) << std::fixed << std::setprecision(3) <<
time_ns
1814class NetworkSimplexBugInvestigation :
public ::testing::Test
1969 double get_flow(
const Net& net)
1974 flow += it.get_curr()->flow;
1980 std::cout <<
"\n--- " << label <<
" ---\n";
1981 std::cout <<
"Arcs:\n";
1982 for (
auto a : net.
arcs())
1984 auto src =
static_cast<Net::Node*
>(a->src_node);
1985 auto tgt =
static_cast<Net::Node*
>(a->tgt_node);
1986 std::cout <<
" Arc(" << (
void*)src <<
"->" << (
void*)tgt <<
"): "
1987 <<
"flow=" << a->flow <<
"/" << a->cap
1988 <<
", cost=" << a->cost
1989 <<
", flow_cost=" << (a->flow * a->cost) <<
"\n";
1991 std::cout <<
"Total flow: " << get_flow(net) <<
"\n";
1992 std::cout <<
"Total cost: " << net.flow_cost() <<
"\n";
2000 std::cout <<
"\n========== NETWORK SIMPLEX BUG INVESTIGATION ==========\n";
2008 size_t pivots =
simplex.run();
2011 std::cout <<
"Pivots performed: " << pivots <<
"\n";
2023 std::cout <<
"\n========== SUMMARY ==========\n";
2024 std::cout <<
"Network Simplex: flow=" <<
flow_ns <<
", cost=" <<
cost_ns
2025 <<
", pivots=" << pivots <<
"\n";
2026 std::cout <<
"Cycle Canceling: flow=" <<
flow_cc <<
", cost=" <<
cost_cc <<
"\n";
2046 std::cout <<
"\n⚠️ COST DIFFERENCE: Network Simplex=" <<
cost_ns
2047 <<
", Cycle Canceling=" <<
cost_cc <<
"\n";
2049 std::cout <<
"Network Simplex found suboptimal solution!\n";
2051 std::cout <<
"Cycle Canceling found suboptimal solution!\n";
2055 std::cout <<
"\n✓ Both algorithms found the same cost\n";
2070 size_t pivots =
simplex.run();
2073 std::cout <<
"Simple network: cost_before=" <<
cost_before
2075 <<
", pivots=" << pivots <<
"\n";
2094 auto stats =
simplex.get_stats();
2100 EXPECT_EQ(stats.total_pivots, stats.phase1_pivots + stats.phase2_pivots);
2108 std::cout <<
"Statistics:\n"
2109 <<
" Total pivots: " << stats.total_pivots <<
"\n"
2110 <<
" Phase I: " << stats.phase1_pivots <<
" (" << stats.phase1_time_ms <<
" ms)\n"
2111 <<
" Phase II: " << stats.phase2_pivots <<
" (" << stats.phase2_time_ms <<
" ms)\n"
2112 <<
" Degenerate: " << stats.degenerate_pivots <<
"\n"
2113 <<
" Tree arcs: " << stats.tree_arcs <<
"\n";
2127 auto stats =
simplex.get_stats();
2132 std::cout <<
"10x10 Grid stats:\n"
2133 <<
" Nodes: " << net.
vsize() <<
", Arcs: " << net.
esize() <<
"\n"
2134 <<
" Pivots: " << stats.total_pivots <<
"\n"
2135 <<
" Time: " << stats.total_time_ms <<
" ms\n";
2148 auto stats =
simplex.get_stats();
2150 std::cout <<
"Dense network:\n"
2151 <<
" Nodes: " << net.
vsize() <<
", Arcs: " << net.
esize() <<
"\n"
2152 <<
" Pivots: " << stats.total_pivots <<
"\n"
2153 <<
" Degenerate: " << stats.degenerate_pivots <<
"\n";
2186 std::cout <<
"Negative costs: before=" <<
cost_before
2198 ::testing::InitGoogleTest(&
argc,
argv);
Simplex algorithm for linear programming.
TEST_F(StaticArenaFixture, simple_fail)
WeightedDigraph::Node Node
Bellman-Ford algorithm for shortest paths with negative weights.
bool has_curr() const noexcept
Return true the iterator has an current arc.
Generic key-value map implemented on top of a binary search tree.
constexpr bool is_empty() const noexcept
Return true if list is empty.
size_t size() const noexcept
Count the number of elements of the list.
Filtered iterator for incoming arcs of a node.
Node * insert_node(Node *p) override
Network Simplex algorithm for minimum cost flow.
Filtered iterator for outcoming arcs of a node.
Linear program solver using the Simplex method.
constexpr size_t vsize() const noexcept
size_t esize() const noexcept
Return the total of arcs of graph.
DynArray< Graph::Node * > nodes
DynArray< Graph::Arc * > arcs
Container< T > arcs_map(GT &g, std::function< T(typename GT::Arc *)> transformation, SA sa=SA())
Map the filtered arcs of a graph to a transformed type.
Net build_grid_network(int rows, int cols, FlowType base_cap=10.0)
Build a grid network for stress testing.
Main namespace for Aleph-w library functions.
DynList< typename Net::Arc * > get_partial_arcs(const Net &net)
Get arcs with partial flow (0 < flow < cap).
Residual_Net< typenameNet::Flow_Type >::Node * build_residual_net(const Net &net, Residual_Net< typename Net::Flow_Type > &rnet, DynMapTree< void *, void * > &arcs)
Build a residual network from a flow network.
size_t size(Node *root) noexcept
Container2< typename Container1::Item_Type > filter(Container1 &container, Operation &operation)
Filter elements that satisfy operation.
Itor2 copy(Itor1 sourceBeg, const Itor1 &sourceEnd, Itor2 destBeg)
Copy elements from one range to another.
std::tuple< size_t, double > max_flow_min_cost_by_cycle_canceling(Net &net, double it_factor=0.4, size_t step=10)
Compute maximum flow at minimum cost using cycle canceling.
void create_residual_arc(const Net &net, PP_Res_Net< Net > &rnet, typename Net::Arc *a)
Create residual arcs for a in the residual network.
size_t max_flow_min_cost_by_network_simplex(Net &net)
Compute maximum flow at minimum cost using Network Simplex.
bool check_residual_net(const Res_Net &net)
Verify residual network consistency.
Feasible_Tree< Net > build_feasible_spanning_tree(const Net &net)
Build feasible spanning tree classification.
DynList< T > maps(const C &c, Op op)
Classic map operation.
Filtered iterator on all the arcs of a graph.
Arc information for multi-commodity flow.
Flow_Type cost(size_t k) const
Get cost for commodity k.
Flow_Type flow(size_t k) const
Get flow for commodity k.
Functor wrapper for maximum flow minimum cost algorithm.
Functor wrapper for Network Simplex algorithm.
Arc type for maximum flow minimum cost networks.
Capacitated flow network with costs associated to arcs.
Flow network implemented with adjacency lists.
Node * insert_node(const Node_Type &node_info)
Insert a new node by copying node_info.
Node * get_source() const
Return an arbitrary source node.
Arc * insert_arc(Node *src_node, Node *tgt_node, const Flow_Type &cap, const Flow_Type &flow, const typename Arc::Arc_Type &arc_info=Arc_Type())
Insert a capacitated arc with an initial flow.
Node * get_sink() const
Return an arbitrary sink node.
Flow_Type flow_value() const
Return the total flow value of the network.
Cost distance functor for Bellman-Ford on residual networks.
static void set_zero(typename Net::Arc *a) noexcept
Reset arc to zero state.
Arc filter for residual networks.
Node information for Network Simplex algorithm.
void verify_flow_conservation(const Net &net)
Maximum flow minimum cost network algorithms.