fn order_sccs(
condensed_graph: &mut Graph<Vec<InvestmentSet>, GraphEdge>,
original_graph: &Graph<InvestmentSet, GraphEdge, Directed>,
)Expand description
Order the members of each strongly connected component using a mixed-integer linear program.
condensed_graph contains the SCCs detected in the original investment graph, stored as
Vec<InvestmentSet> node weights. Single-element components are already acyclic, but components
with multiple members require an internal ordering so that the investment algorithm can treat
them as near-acyclic chains, minimising potential disruption.
To rank the members of each multi-node component, we construct a mixed integer linear program (MILP). This MILP is adapted from the classical Linear Ordering Problem:
Marti, Rafael, and G Reinelt. The Linear Ordering Problem: Exact and Heuristic Methods in Combinatorial Optimization. 1st ed. 2011. Berlin: Springer-Verlag, 2011. Web.
The main features of the MILP are:
- Binary variables
x[i][j]represent whether marketishould appear before marketj. - Antisymmetry constraints force each pair
(i, j)to choose exactly one direction (i.e. ificomes beforej, thenjcannot be beforei). - Transitivity constraints prevent 3-cycles, ensuring the resulting relation is acyclic (i.e. if
icomes beforejandjcomes beforek, thenkcannot come beforei). - The objective minimises the number of “forward” edges (edges that would point from an earlier
market to a later one), counted within the original SCC and treated as unit penalties. A small
bias (<1) is added to nudge exporters earlier without outweighing the main objective (a bias
1 would instead prioritise exporters even if it created extra conflicts in the final order).
Once the MILP is solved, markets are scored by the number of pairwise “wins” (how many other markets they precede). Sorting by this score — using the original index as a tiebreaker to keep relative order stable — yields the final sequence that replaces the SCC in the condensed graph. At least one pairwise mismatch is always inevitable (e.g. where X is solved before Y, but Y may consume X, so the demand for X cannot be guaranteed upfront).
§Example
Suppose three markets (A, B and C) form a cycle in the original graph with the following edges:
A ← B ← C ← AAdditionally, C has an outgoing edge to a node outside the cycle.
The costs matrix in the MILP is set up to penalise any edge that points “forward” in the final order: if there’s an edge from X to Y we prefer to place Y before X so the edge points backwards:
| | A | B | C |
| A | 0 | 0 | 1 |
| B | 1 | 0 | 0 |
| C | 0 | 1 | 0 |On top of this, we give a small preference to markets that export outside the SCC, so nodes with
outgoing edges beyond the cycle are pushed earlier. This is done via an EXTERNAL_BIAS
parameter (B) applied to the cost matrix:
| | A | B | C |
| A | 0 | 0 | 1 + B | i.e. extra penalty for putting A before C
| B | 1 | 0 | 0 + B | i.e. extra penalty for putting B before C
| C | 0 | 1 | 0 |Solving this problem with binary decision variables for each x[i][j], and constraints to enforce
antisymmetry and transitivity, yields optimal decision variables of:
x[A][B] = 1 (A before B)
x[A][C] = 0 (C before A)
x[B][A] = 0 (A before B)
x[B][C] = 0 (C before B)
x[C][A] = 1 (C before A)
x[C][B] = 1 (C before B)From these, summing the number of times each market is preferred over another gives an optimal order of:
C, A, B- By scheduling C before A before B, the edges C ← A and A ← B incur no cost because their targets appear earlier than their sources.
- The preference towards having exporter markets early in the order keeps C at the front.
- As with any SCC, at least one pairwise violation is guaranteed. In this ordering, the only pairwise violation is between B and C, as C is solved before B, but B may consume C.
The resulting order replaces the original InvestmentSet::Cycle entry inside the condensed
graph, providing a deterministic processing sequence for downstream logic.