Expand description
§Chapter 5.4 — FTRAN and BTRAN, dense and hypersparse
§Purpose
The simplex method needs α_q = B⁻¹ a_q (FTRAN, forward transformation)
and ρ_r = B⁻ᵀ e_r, y = B⁻ᵀ c_B (BTRAN, backward transformation).
This chapter applies the factors of Chapter 5.3 and the row etas of
Chapter 5.5 to a right-hand side, in one of two ways:
- the dense Algorithms F and B run over every elimination step,
skipping exact zeros:
O(m + nnz(L) + nnz(U) + nnz(etas))whatever the right-hand side; - the hypersparse Algorithms HF and HB first compute, by depth-first
search in the graphs of the factors, the set of entries that can
become nonzero (the reach of the right-hand side, Gilbert & Peierls
1988), and then perform only the operations of the reach, in a
topological order. Their cost is proportional to the number of
entries and factor nonzeros actually involved — on the large sparse LPs
(Kennington
ken-*,pds-*) a handful out ofm ≈ 10⁵, which is what Hall & McKinnon (2005) call hypersparsity.
The choice between the two is automatic, per call (policy below).
§Notation
After t updates the factor represents
B = Pᵀ L R₁⁻¹ ⋯ R_t⁻¹ U Qᵀ,where R_e = I − e_{p} μ_eᵀ is the row eta of update e (target row
p, multipliers μ_e on rows pivoted after p). FTRAN maps a vector
indexed by rows to one indexed by positions; BTRAN the reverse.
For a row p let q(p) = q_{step(p)} be the position pivoted with it,
and for a position q let p(q) = p_{step(q)}.
The four graphs of the hypersparse solves have an arc a → b when
the value at b is modified by an operation that reads the value at
a:
G_Lon rows:p → ifor every multiplierl_ipof theLeta with pivot rowp(column-wiseL, as stored);G_Uon rows:p → ifor every off-diagonalu_{i q(p)}of columnq(p)ofU(Uby columns);G_Uᵀon positions:q → jfor every off-diagonalu_{p(q) j}of rowp(q)ofU(Uby rows);G_Lᵀon rows:i → pfor every multiplierl_ip(Lby rows, a transposed copy built once per factorization).
The row etas are applied in creation order (FTRAN) or in reverse
creation order (BTRAN); their dependencies are held by two lists per
row: the etas that read row k (k among their p_k) and the etas
that target row p.
§Algorithm F (dense FTRAN: solve B x = b)
F1. [L.] For each L eta in pivot order (pivot row p, multipliers
l_ip): if y_p ≠ 0, set y_i ← y_i − l_ip y_p.
F2. [R.] For each row eta in creation order (target p): set
y_p ← y_p − Σ_k μ_k y_{p_k}. The vector y now holds the spike
R L⁻¹ b — recorded by crate::LuFactor::ftran_for_update.
F3. [U.] For the steps s in decreasing order, with pivot (p_s, q_s):
x_{q_s} ← y_{p_s} / u_{p_s q_s}; if nonzero, y_i ← y_i − u_{i q_s} x_{q_s} for the entries of column q_s of U (all in rows of earlier
steps).
§Algorithm B (dense BTRAN: solve Bᵀ y = c)
B1. [Uᵀ.] For the steps s in increasing order:
w_{p_s} ← c_{q_s} / u_{p_s q_s};
if nonzero, c_j ← c_j − u_{p_s j} w_{p_s} for the entries of row
p_s of U (all in positions of later steps).
B2. [Rᵀ.] For each row eta in reverse creation order (target p): if
w_p ≠ 0, w_{p_k} ← w_{p_k} − μ_k w_p.
B3. [Lᵀ.] For each L eta in reverse pivot order (pivot row p):
w_p ← w_p − Σ_i l_ip w_i. Then y = w.
Correctness: F1–F3 apply L⁻¹, R_t ⋯ R_1 and U⁻¹ (with the
permutations implicit in the indexing) to b; B1–B3 apply the
transposes in the opposite order.
§Algorithm D (reach: depth-first search, Gilbert & Peierls)
Given a graph G and a set S of start nodes, produce the nodes
reachable from S in a topological order (every arc a → b between
reached nodes has a before b).
D1. [Start.] Take a fresh mark (a stamp: no clearing). Empty the output
list post. For each s ∈ S not yet marked, mark it and push
(s, 0) on the stack; then run D2 until the stack is empty.
D2. [Step.] Let (v, k) be the top of the stack. If v has a k-th
successor w, advance k; if w is unmarked, mark it and push
(w, 0). Otherwise pop v and append it to post (v is
finished).
D3. [Order.] A node finishes after every node reachable from it, so
post read backwards is a topological order.
The stack is explicit (no recursion: the paths in G_L can be 10⁵
long). Cost: O(|reach| + arcs out of the reach).
§Algorithm HF (hypersparse FTRAN)
The right-hand side b is given with its pattern.
HF1. [Load.] Copy the nonzeros of b into the row work array y;
empty b (it receives the result).
HF2. [Reach of L.] Run Algorithm D on G_L from the rows of HF1.
HF3. [Apply L.] For each reached row p in topological order: if p
is the pivot of an L eta and y_p ≠ 0, set y_i ← y_i − l_ip y_p.
The reached rows form the list Λ (marked).
HF4. [Row etas.] Put in a min-priority queue every eta that reads a row
of Λ. While the queue is not empty, take the smallest eta e
(target t): y_t ← y_t − Σ_k μ_k y_{p_k}; if t ∉ Λ, add it to
Λ and queue the etas after e that read t. (An eta before e
that reads t was applied — or skipped — while y_t was still
zero, exactly as in F2.) For crate::LuFactor::ftran_for_update,
record the spike y on Λ.
HF5. [Reach of U.] Run Algorithm D on G_U from Λ.
HF6. [Apply U.] For each reached row p in topological order:
x_{q(p)} ← y_p / u_{p q(p)}, y_p ← 0; if x_{q(p)} ≠ 0, set
y_i ← y_i − u_{i q(p)} x_{q(p)} along column q(p). The pattern
of the result is the set of positions q(p) of the reach.
§Algorithm HB (hypersparse BTRAN)
HB1. [Load.] Copy the nonzeros of c into the position work array;
empty c.
HB2. [Reach of Uᵀ.] Run Algorithm D on G_Uᵀ from the positions of HB1.
HB3. [Apply Uᵀ.] For each reached position q in topological order:
w_{p(q)} ← c_q / u_{p(q) q}, c_q ← 0; if nonzero,
c_j ← c_j − u_{p(q) j} w_{p(q)} along row p(q). The rows p(q)
form the list Λ (marked).
HB4. [Row etas, transposed.] Put in a max-priority queue every eta whose
target is in Λ. While the queue is not empty, take the largest eta
e (target t): if w_t ≠ 0, w_{p_k} ← w_{p_k} − μ_k w_t; for
every p_k ∉ Λ, add it to Λ and queue the etas before e that
target p_k. (The etas after e that target p_k already ran,
with w_{p_k} = 0: no-ops in B2 too.)
HB5. [Reach of Lᵀ.] Run Algorithm D on G_Lᵀ from Λ.
HB6. [Apply Lᵀ.] For each reached row i in topological order: if
w_i ≠ 0, set w_p ← w_p − l_ip w_i for every multiplier of row
i of L. The result y = w has the reach as pattern.
The direction of the arcs is the delicate point. In FTRAN L and U
are used by columns (scatter: a known value pushes into the rows it
modifies), so the graphs are those of the stored columns. In BTRAN the
dense algorithm uses U by rows (B1 is already a scatter, along row
p(q): arcs q → j) but L by columns as a gather (B3 sums over the
column of eta p): a gather cannot be driven by a reach, so HB6 turns it
into a scatter along the rows of L (i → p), which needs the
transposed copy of L. The row etas are the opposite: F2 is a gather
(driven by the “readers” lists) and B2 a scatter (driven by the
“targets” lists).
§Choice of the algorithm (alternation policy)
Following Hall & McKinnon (2005, §4) and HiGHS, the hypersparse
algorithm is used for a call iff
(a) the right-hand side is in sparse mode (it has a pattern);
(b) its density count/m is at most
LuOptions::hyper_rhs_density (0.10);
(c) the expected density of the result — an exponential moving
average, with weight HYPER_HISTORY_WEIGHT for the newest
result, of the result densities of the previous calls of the same
kind (FTRAN, BTRAN, FTRAN for update; kept across factorizations,
starting at 0) — is at most
LuOptions::hyper_result_density
(0.10).
When the result fills in, the reach costs more than the dense sweep
(the search visits every arc once, then the numerical pass visits them
again), so (c) switches a kind of operation to the dense algorithms
after about three dense results, and back once results are sparse again
(the dense algorithms measure their result density exactly). The
per-kind statistics (SolveStats) are in crate::LuStats.
§Division of labour (second edition)
Steps F2, B2, HF4 and HB4 — the row etas — belong to the basis-update
policy (Chapter 5.5): they are the methods
BasisUpdate::apply_ftran, BasisUpdate::apply_btran,
BasisUpdate::apply_ftran_hyper and BasisUpdate::apply_btran_hyper
of crate::ForrestTomlin, called at exactly the place where the first
edition ran them inline, with the same work arrays. Everything else is
here, on the stored factors.
§Invariants
(V1) On return the SparseVec is in sparse mode. After a dense solve
its pattern is the exact support of the result (in increasing
order); after a hypersparse solve it is the symbolic reach, a
superset of the support that may contain explicit zeros (allowed by
the invariant (V2) of SparseVec; call SparseVec::tidy to
drop zeros and tiny entries). Computing the exact support would
cost one more pass for no benefit to the simplex method.
(V2) Both work arrays are zero between calls.
(V3) The dense and the hypersparse algorithms perform the same
operations except for the order of independent updates (and
HB6, which sums the terms of B3 one at a time): their results agree
to rounding (property test: relative error ≤ 1e-12).
§Complexity
Dense: O(m + nnz(L) + nnz(U) + nnz(etas)). Hypersparse:
O(r + f + e log e) with r the reach sizes, f the factor nonzeros
in the columns (or rows) of the reach and e the number of row etas
involved.
§References
J. R. Gilbert and T. Peierls, “Sparse partial pivoting in time
proportional to arithmetic operations”, SIAM J. Sci. Stat. Comput. 9(5),
1988 (the reach by depth-first search); J. A. J. Hall and K. I. M.
McKinnon, “Hyper-sparsity in the revised simplex method and how to
exploit it”, Comput. Optim. Appl. 32, 2005 (hypersparse FTRAN/BTRAN,
the density thresholds); T. A. Davis, Direct Methods for Sparse Linear
Systems (2006), §3.2 (cs_reach, cs_dfs); Maros (2003), §5.4–5.5;
Forrest & Tomlin (1972); Suhl & Suhl (1990), §4; Koberstein (2005),
§5.3; HiGHS HFactor (studied, not copied).
Structs§
- Solve
Stats - Counters of one kind of solve (FTRAN, BTRAN or FTRAN for update),
accumulated over the life of the
Lu(not reset by a factorization). The contract’s mean densities are the methodsSolveStats::mean_rhs_densityandSolveStats::mean_result_densityover exact sums (no division per call).
Constants§
- HYPER_
HISTORY_ WEIGHT - Weight of the newest result in the moving average of the result density of each kind of solve (policy (c) of the module documentation).