105# ifndef TPL_MULTICOMMODITY_H
106# define TPL_MULTICOMMODITY_H
129 template <
typename Node,
typename Flow_Type =
double>
143 const std::string&
_name =
"")
157 template <
typename Arc_Info = Empty_Class,
typename FT =
double>
245 template <
class NodeT = Graph_Anode<Empty_Class>,
246 class ArcT = MCF_Arc<Empty_Class,
double>>
271 <<
"Commodity index " <<
k <<
" out of range";
290 const std::string& name =
"")
293 commodities.emplace_back(
id, source, sink, demand, name);
296 for (
typename Base::Arc_Iterator it(*
this); it.has_curr(); it.next_ne())
297 it.get_curr()->init_commodities(
id + 1);
314 auto arc = Base::insert_arc(src, tgt);
315 arc->capacity = capacity;
316 arc->base_cost = cost;
326 for (
typename Base::Node_Iterator it(*
this); it.has_curr(); it.next_ne())
340 for (
typename Base::Arc_Iterator it(*
this); it.has_curr(); it.next_ne())
342 auto arc = it.get_curr();
344 sum += arc->flow(
k) * arc->cost(
k);
356 out_flow += it.get_curr()->flow(
comm.id);
360 in_flow += it.get_curr()->flow(
comm.id);
362 if (std::abs((out_flow - in_flow) -
comm.demand) > 1e-6)
371 for (
typename Base::Arc_Iterator it(*
this); it.has_curr(); it.next_ne())
373 auto arc = it.get_curr();
374 if (arc->total_flow() > arc->capacity + 1e-6)
383 std::cout <<
"=== Multi-commodity Network ===\n"
384 <<
"Nodes: " << this->vsize() <<
"\n"
385 <<
"Arcs: " << this->esize() <<
"\n"
389 std::cout <<
" [" << c.id <<
"] " << c.name
390 <<
": demand=" << c.demand <<
"\n";
392 std::cout <<
"Total cost: " <<
total_cost() <<
"\n";
405 template <
typename Flow_Type =
double>
484 auto start_time = std::chrono::high_resolution_clock::now();
486 const size_t K =
net.num_commodities();
489 if (K == 0 || E == 0)
497 net.build_node_index();
508 for (
size_t k = 0;
k < K; ++
k)
512 auto arc = it.get_curr();
513 lp.put_objetive_function_coef(
var_idx, arc->cost(
k));
522 auto arc =
ait.get_curr();
523 auto tgt =
static_cast<Node*
>(arc->tgt_node);
533 for (
size_t k = 0;
k < K; ++
k)
535 const auto&
comm =
net.get_commodity(
k);
539 auto node =
nit.get_curr();
542 if (node ==
comm.sink)
547 if (node ==
comm.source)
557 auto arc =
ait.get_curr();
566 for (
auto it =
in_list.
get_it(); it.has_curr(); it.next_ne())
568 auto arc = it.get_curr();
578 lp.put_eq_restriction(
row.data());
586 auto arc = it.get_curr();
591 for (
size_t k = 0;
k < K; ++
k)
596 lp.put_restriction(
row.data());
600 lp.prepare_linear_program();
618 for (
size_t k = 0;
k < K; ++
k)
622 auto arc = it.get_curr();
624 if (flow < 0) flow = 0;
626 arc->set_flow(
k, flow);
633 auto end_time = std::chrono::high_resolution_clock::now();
634 result.
solve_time_ms = std::chrono::duration<double, std::milli>(
647 const size_t K =
net.num_commodities();
651 std::cout <<
"=== MCF LP Formulation ===\n"
652 <<
"Variables: " << (K * E) <<
" (K=" << K <<
" × E=" << E <<
")\n"
653 <<
"Constraints: " << (K *
V + E)
654 <<
" (flow: " << (K *
V) <<
", capacity: " << E <<
")\n\n";
656 std::cout <<
"Objective: minimize Σ c_ij^k * x_ij^k\n\n";
658 std::cout <<
"Commodities:\n";
659 for (
size_t k = 0;
k < K; ++
k)
661 const auto& c =
net.get_commodity(
k);
662 std::cout <<
" k=" <<
k <<
": demand=" << c.demand <<
"\n";
Simplex algorithm for linear programming.
Exception handling system with formatted messages for Aleph-w.
#define ah_out_of_range_error_if(C)
Throws std::out_of_range if condition holds.
WeightedDigraph::Node Node
bool has_curr() const noexcept
Return true the iterator has an current arc.
Generic directed graph (digraph) wrapper template.
T & append(const T &item)
Append a new item by copy.
Generic key-value map implemented on top of a binary search tree.
Pair * insert(const Key &key, const Data &data)
Insert a key-value pair.
Data & find(const Key &key)
Find the value associated with key.
void empty()
remove all elements from the set
size_t size() const noexcept
Count the number of elements of the list.
Filtered iterator for incoming arcs of a node.
Multi-commodity flow network (directed graph).
const std::vector< CommodityType > & get_commodities() const
Get all commodities.
MCF_Graph()=default
Default constructor.
void print_summary() const
Print network summary.
DynMapTree< Node *, size_t > node_to_idx
Flow_Type total_cost() const
Total flow cost across all commodities.
size_t add_commodity(Node *source, Node *sink, Flow_Type demand, const std::string &name="")
Add a commodity to the network.
void build_node_index()
Build node index mapping (call after all nodes inserted)
std::vector< CommodityType > commodities
Arc * insert_arc(Node *src, Node *tgt, Flow_Type capacity, Flow_Type cost=0)
Insert arc with capacity and cost.
const CommodityType & get_commodity(size_t k) const
Get commodity by index.
bool capacities_respected() const
Check capacity constraints.
size_t num_commodities() const
Get number of commodities.
size_t get_node_index(Node *p) const
Get node index.
bool demands_satisfied() const
Check if all demands are satisfied.
typename Arc::Flow_Type Flow_Type
Multi-commodity flow solver using LP formulation.
typename Net::Flow_Type Flow_Type
size_t var_index(size_t k, size_t arc_idx) const
Result solve()
Solve the multi-commodity flow problem.
void print_formulation(size_t max_constraints=10) const
Print LP formulation (for debugging).
MCF_LP_Solver(Net &network)
Construct solver for a network.
DynMapTree< Arc *, size_t > arc_to_idx
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.
auto get_it() const
Return a properly initialized iterator positioned at the first item on the container.
Main namespace for Aleph-w library functions.
MCF_Result< typename Net::Flow_Type > solve_multicommodity_flow(Net &net)
Solve multi-commodity flow problem.
DynList< T > maps(const C &c, Op op)
Classic map operation.
T sum(const Container &container, const T &init=T{})
Compute sum of all elements.
Iterator over arcs of a graph.
Commodity definition for multi-commodity flow.
Node * source
Source node for this commodity.
Commodity(size_t _id, Node *_src, Node *_sink, Flow_Type _demand, const std::string &_name="")
Full constructor.
size_t id
Unique commodity identifier.
Flow_Type demand
Required flow amount.
std::string name
Optional descriptive name.
Node * sink
Sink node for this commodity.
Commodity()
Default constructor.
Arc information for multi-commodity flow.
Flow_Type cost(size_t k) const
Get cost for commodity k.
Flow_Type capacity
Arc capacity (shared)
MCF_Arc(Flow_Type cap, Flow_Type cost=0)
Constructor with capacity and cost.
Flow_Type flow(size_t k) const
Get flow for commodity k.
Flow_Type base_cost
Default cost per unit flow.
Flow_Type residual() const
Residual capacity.
MCF_Arc()=default
Default constructor.
Flow_Type total_flow() const
Total flow on this arc (sum of all commodities)
void set_flow(size_t k, Flow_Type f)
Set flow for commodity k.
MCF_Arc(const Arc_Info &)
Constructor from Arc_Info (required by graph framework)
void set_cost(size_t k, Flow_Type c)
Set cost for commodity k.
FT Flow_Type
Type for flow values.
std::vector< Flow_Type > commodity_cost
Cost per commodity (optional)
MCF_Arc(Arc_Info &&)
Constructor from Arc_Info rvalue (required by graph framework)
void init_commodities(size_t K)
Initialize for K commodities.
std::vector< Flow_Type > commodity_flow
Flow per commodity.
Multi-commodity flow result.
std::vector< Flow_Type > commodity_costs
Cost per commodity.
Flow network implemented with adjacency lists.
typename Arc::Flow_Type Flow_Type
Capacity/flow numeric type.
Array-based graph implementation.
Dynamic key-value map based on balanced binary search trees.