Repository navigation
Add a PowerMean off-transversal, target t<1 minimizer - #95
Merged
Merged
Conversation
`_transversal_system` builds the transversal-tight difference system (maximum-product transversal, transversal log magnitudes, the edge list of off-transversal entries, tight components, and the feasible start), and `_contract_system` reduces it to one unknown per tight component. `_finish_cover` applies the balance convention, checks that the scales are representable, exponentiates, and certifies the cover. `_cover_min_abslog2` now calls these helpers; its results are unchanged. Assisted-by: Claude Opus 5.5 <noreply@anthropic.com>
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #95 +/- ##
==========================================
- Coverage 98.84% 98.71% -0.14%
==========================================
Files 23 25 +2
Lines 6343 7093 +750
==========================================
+ Hits 6270 7002 +732
- Misses 73 91 +18 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
`cover_transversal(PowerMean{p}(), A; target)` returns the hard cover
tight on the maximum-product transversals that minimizes
∑ (r^p - 1 - p*log(r/target)*target^p)/p over the coverage ratios r of
the other entries, pushing them toward `target`.
The solver is a primal active-set Newton method on the contracted
row-scale difference system: rows joined by zero-slack entries move
together as groups, Newton steps solve weighted graph-Laplacian systems
on the groups (dense or sparse Cholesky, or conjugate gradients over the
fill budget), a ratio test and Armijo backtracking keep every iterate
feasible, and at stationary points a maximum-flow test on each group's
active entries either certifies the KKT conditions or yields a set of
rows whose scales decrease, releasing entries. Every iterate is a hard
cover tight on the transversal, so an unconverged solve warns and still
returns one. Statistics are returned as `BalancedCoverStats`.
The objective's terms can span many orders of magnitude, so the solver
works at the resolution of each group's terms. The gradient and the
line-search slope sum the `target^p` part by group with integer counts,
so that the slack changes of a group with as many entries leaving as
entering cancel exactly. A ridge for a Newton matrix that roundoff makes
indefinite is relative to each diagonal entry, so it does not swamp the
curvature of groups whose terms are all small. In each weakly connected
part, the group pinned to remove the common shift is the one whose
gradient has the largest terms: the pinned group's gradient carries the
others' roundoff, which is then smallest relative to its own terms. A
Newton step whose slope is nonnegative but within the roundoff of the
groups' gradients is at the resolution of the arithmetic: the groups are
taken to be stationary and the multiplier test decides whether to
continue, so `converged` can hold with `gradnorm > tol`.
`cover_transversal(AbsLog{2}(), A)` and its mutating form forward to
the existing solver. The Ipopt extension adds the reference
`cover_transversal_jump(::PowerMean, A; target)`, and the Unitful
extension forwards the new methods.
test/balanced.jl checks the maximum-flow multiplier test on small
digraphs, the line search where slack changes cancel, where the slope is
at roundoff, and where an entry at zero slack blocks the step, the
covariance of a solve whose groups' terms differ greatly in size, and
the solver against the Ipopt reference (committed 5×5 matrices, random
sparse patterns, 0/1 matrices), against an extended-precision solve for
p = 4, the KKT identity across a block-triangular cut, a group holding
an inactive entry, the minimax ratio for large p, covariance,
permutation equivariance, independence of the transversal used, sparse
and conjugate-gradient solves, element types, generic axes, the
iteration limit, and the argument errors. The manual describes the new
method.
Assisted-by: Claude Opus 5.5 <noreply@anthropic.com>
`_strong_components(ptr, heads)` labels the strongly connected components of a digraph given in compressed adjacency form, numbered in reverse topological order. `_tight_components` calls it on the zero-residual entries. Assisted-by: Claude Opus 5.5 <noreply@anthropic.com>
`cover_transversal(ϕ::PowerMean{p}, A; target, maxbalance=true)` and its
mutating form max-balance the scales within each fully indecomposable
block of `A` (Hook, Pestana, Tisseur & Hogg 2019, Algorithm 3.10:
max-plus policy iteration for a cycle of largest mean, a shift by its
bias, contraction of the cycle) and then minimize the PowerMean objective
with a target ratio over the entries joining different blocks, by the
active-set Newton method on one scale per block. The products are
unique and scale-covariant.
A cycle mean accumulates the roundoff of up to `nv` weights, so the
policy iteration treats cycle means within `nv * tol` of each other as
equal; with `tol` as the threshold the comparisons are not transitive
and the iteration can cycle among tied cycles.
`BalancedCoverStats` records `maxbalanced` and the number of fully
indecomposable blocks, `nblocks`, for every solve.
test/maxbalance.jl covers Example 3.11 of Hook et al. (2019), policy
iteration on nearly equal cycle means, the cut balance by brute force
and the minimax ratio on random fully indecomposable matrices,
agreement with an independent implementation of their Algorithm 3.10,
block-triangular matrices (the KKT identity across each cut, an active
entry between blocks, covariance, the products of each block alone),
tied transversals, sparse and wrapped inputs, element types, and the
mutating form.
Assisted-by: Claude Opus 5.5 <noreply@anthropic.com>
cover_transversal gains the PowerMean method and its maxbalance keyword, new public functionality since 1.1.0. Assisted-by: Claude Fable 5.1 <noreply@anthropic.com>
timholy
force-pushed
the
teh/maxbalance
branch
from
October 24, 2026 10:50
54b415a to
e251706
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This adds a solver for a new approach to asymmetric square matrices: "make them as diagonally-dominant as possible." In the context of an asymmetric matrix, "diagonal" = "transversal." This aims for a target coverage ratio < 1 (default t = 0.01) for the off-transversal entries. It also adds a
maxbalanceoption to compare against Hook, Pestana, Tisseur & Hogg 2019, Algorithm 3.10.On a benchmark suite, the conditioning numbers are often improved by several fold over the older transversal-tight minimal cover, which itself was already a significant advance on the minimal cover.