How can a matrix reveal that a system is structurally underdetermined before you solve a single equation? The Dulmage–Mendelsohn decomposition answers by ignoring the numerical values for a moment and studying where the nonzeros are. It turns a sparse matrix into a bipartite graph, finds a maximum matching, and uses alternating-path structure to separate underdetermined, well-determined and overdetermined parts.
This article teaches the Dulmage–Mendelsohn decomposition as a Learning Hall progression from a simple rows-versus-columns picture to professional sparse-linear-system engineering. It complements the broader Bipartite Matching article and the Reverse Cuthill–McKee article. Its distinct job is to show how matching structure becomes a canonical decomposition of equations, variables and sparse matrix blocks.
Quick Read
- A sparse matrix can be viewed as a bipartite graph: rows on one side, columns on the other, and a graph edge wherever the matrix has a structural nonzero.
- A maximum matching pairs as many rows and columns as possible through nonzero positions.
- The size of that maximum matching is the matrix’s structural rank.
- Unmatched vertices and alternating paths reveal regions that are structurally short of equations, structurally balanced, or structurally short of variables.
- Row and column permutations can expose block-triangular structure, allowing smaller subproblems and clearer diagnostics.
- The numerical rank can still be lower than the structural rank: pattern alone does not protect you from unlucky or dependent values.
1. Beginner Level: Turn a Matrix into a Graph
Suppose a matrix has rows r₁, r₂, … representing equations and columns x₁, x₂, … representing variables. Draw one vertex for every row and one for every column. If entry A[i,j] is structurally nonzero, draw an edge between row rᵢ and column xⱼ.
The actual number in the matrix does not matter for this first structural view. A coefficient of 7, −0.001 or an unknown nonzero parameter all create the same graph edge. A structural zero creates no edge.
This change of representation is the first major idea. A difficult-looking matrix question becomes a graph question: which rows can be paired uniquely with which columns?
2. Maximum Matching: Give Each Row a Different Column
A matching is a set of graph edges that share no endpoints. In matrix language, it chooses nonzero entries with no two in the same row or column. A maximum matching chooses as many such entries as possible.
If every column of a square matrix can be matched to a different row, the sparsity pattern admits a zero-free diagonal after suitable permutations. If only k pairs can be formed, then the structural rank is k. MATLAB’s dmperm documentation states this directly: for a matching vector p, sprank(A) = sum(p > 0).
Do not confuse structural rank with ordinary numerical rank. Structural rank asks what rank is possible for generic nonzero values consistent with the pattern. Numerical rank asks what rank the actual numbers produce. A pattern can support full rank and still become singular because of special numerical dependencies.
3. A Small System with Three Different Structural Jobs
Consider four equations and four variables with these structural connections:
- r₁ connects to x₁ and x₂;
- r₂ connects to x₃;
- r₃ also connects to x₃;
- r₄ connects to x₄.
The component containing r₁ has one equation competing over two possible variables: structurally, there is more variable freedom than equation constraint. The component containing r₂ and r₃ has two equations depending on one variable: structurally, equations outnumber available variable slots. The r₄–x₄ component is balanced.
A maximum matching can match three row–column pairs but not all four. More importantly, the decomposition tells us where the structural imbalance lives rather than returning only the number 3.
4. Why One Rank Number Is Not Enough
If a sparse system has structural rank 997 out of 1000, knowing “three dimensions are missing” is useful but incomplete. A modeller, compiler or solver wants to know which equations and variables are implicated. Are all three deficiencies in one subsystem? Are there independent problem regions? Can a well-determined block be solved separately?
Dulmage–Mendelsohn decomposition provides that geography. It reorganises the graph around maximum-matching structure so that deficiency, balance and dependency become visible as regions.
5. Alternating Paths: The Motion That Reveals the Structure
Once a maximum matching M is fixed, an alternating path switches between edges not in M and edges in M. Starting from an unmatched row or column, these paths reveal which vertices can exchange matching responsibility without reducing the matching size.
This is easier to understand as a chain of reassignment. If x₂ is currently unmatched but is adjacent to r₁, and r₁ is matched to x₁, then the path x₂–r₁–x₁ says, “x₂ could take r₁’s slot if x₁ becomes free.” Longer alternating paths propagate that possibility through the graph.
Strong learners should physically trace alternating paths on paper before coding them. It is one of those ideas that looks abstract in notation but becomes obvious when you follow who would have to give up a match for whom.
6. Coarse Decomposition: Under, Well and Over
For sparse systems, the coarse Dulmage–Mendelsohn view separates structural roles that are often described as underdetermined, well-determined and overdetermined. MATLAB exposes this through row and column permutations and coarse block boundaries; the resulting permuted matrix has a structured block form with guaranteed zero regions.
- Underdetermined region: there are structurally too many variable-side degrees of freedom relative to available independent equations.
- Well-determined region: the structural matching can balance the corresponding row and column sets.
- Overdetermined region: there are structurally more equation constraints than distinct variable positions can support.
These words describe structural incidence, not whether a particular real-world model is scientifically valid. A redundant equation can be intentional; an underdetermined subsystem can be solved with regularisation or additional information. The decomposition is diagnosis, not judgement.
7. Fine Decomposition: Break the Balanced Core into Smaller Blocks
The well-determined part can often be decomposed further. After matching, one can orient or contract relationships so that strongly connected structure reveals smaller irreducible blocks. In sparse-matrix software, the resulting row and column permutations expose a block upper-triangular form.
This matters because a 100,000-variable system that is structurally one giant problem is very different from a system that permutes into thousands of smaller blocks with a dependency order. The arithmetic may be identical in principle, but the execution plan, diagnostics and opportunities for parallel work change dramatically.
8. Conceptual Algorithm
build bipartite graph G from the nonzero pattern of A
M = maximum_matching(G)
identify unmatched row-side and column-side vertices
follow alternating paths relative to M
classify vertices by which unmatched side can reach them
separate structurally deficient / balanced regions
inside the balanced core:
build the directed dependency representation induced by M
find strongly connected components
topologically order those components
return row permutation, column permutation, and block boundaries
Real implementations differ in details and data structures. The important learning sequence is stable: matching first, alternating reachability second, finer component structure third.
9. A Transparent Python Structural-Rank Exercise
import numpy as np
from scipy.sparse import csr_matrix
from scipy.sparse.csgraph import maximum_bipartite_matching, structural_rank
A_pattern = csr_matrix(np.array([
[1, 1, 0, 0],
[0, 0, 1, 0],
[0, 0, 1, 0],
[0, 0, 0, 1],
], dtype=int))
matching = maximum_bipartite_matching(A_pattern, perm_type="row")
rank = structural_rank(A_pattern)
print("matching:", matching)
print("structural rank:", rank)
This exercise deliberately stops before implementing a full DM permutation. First make the matching and structural-rank ideas concrete. Then compare your own decomposition logic with a production routine such as MATLAB dmperm or HSL_MC79.
10. What the Permutation Buys You
- Diagnostics: locate unmatched equations or variables instead of reporting only “singular structure”.
- Block solves: expose subproblems that can be processed in dependency order.
- Reduced factorisation work: sparse direct methods can exploit block triangular structure before numerical factorisation.
- Model debugging: reveal equation-variable incidence mistakes, missing constraints and duplicated structural roles.
- Preprocessing: give later ordering algorithms a cleaner problem to work on.
Timothy Davis describes Dulmage–Mendelsohn decomposition as a useful permutation before sparse LU and QR factorisation: first obtain a zero-free diagonal where possible, then expose block triangular form.
11. Complexity: Separate the Matching Cost from the Decomposition Cost
The total runtime depends heavily on the maximum-matching algorithm and on graph sparsity. Once a maximum matching is available, alternating reachability and strongly connected component passes are graph traversals that can be organised in time linear in the relevant vertices and edges. For large sparse systems, matching is commonly the dominant conceptual stage.
Do not quote one universal Big-O number for “the DM algorithm” without naming the matching method and representation. Professional complexity analysis should identify which subroutine creates the bound.
12. Failure Modes Strong Learners Should Test
- Confusing numerical zero with structural zero: a value that happens to be zero at runtime may or may not belong in the structural pattern.
- Confusing structural rank with numerical rank: generic possibility is not the same as the rank of one numerical instance.
- Using a non-maximum matching: the decomposition depends on maximum-matching structure, not an arbitrary greedy pairing.
- Forgetting rectangular matrices: DM decomposition is especially useful when row and column counts differ.
- Mixing row and column permutation conventions: library APIs differ in what a returned permutation indexes.
- Assuming one maximum matching is the whole story: alternating paths encode flexibility across maximum matchings.
- Ignoring isolated rows or columns: they are immediate structural deficiency signals.
- Dense conversion: materialising a huge sparse matrix as dense can destroy the very computational advantage you are trying to exploit.
13. Professional-Level Engineering
Production sparse software stores only structural nonzeros, uses matching algorithms designed for sparse graphs, and returns permutations rather than physically copying large matrices repeatedly. The HSL_MC79 package, for example, computes maximum matching and coarse/fine Dulmage–Mendelsohn decompositions for rectangular sparse matrices. MATLAB’s dmperm similarly returns row and column permutations plus block-boundary information.
At scale, the key questions are not only “is the decomposition mathematically correct?” but also: Does it preserve sparse storage? Are permutation arrays 32-bit or 64-bit safe? Can symbolic preprocessing be reused across many numerical solves with the same sparsity pattern? Are structural warnings surfaced to the modeller before expensive factorisation begins?
14. How to Learn It Without Memorising It
Programming-education research repeatedly supports scaffolds that make structure visible before demanding full code production. For this algorithm, that means working with tiny bipartite graphs, predicting the maximum matching, tracing alternating paths, and explaining why each vertex belongs to its region before implementing the machinery.
- Predict: identify unmatched rows and columns by inspection.
- Trace: mark matched and unmatched edges in different pencil styles and follow alternating paths.
- Explain: state what each region means in equation-variable language.
- Modify: add one edge and predict which region changes before recomputing.
- Implement: code matching, reachability and component logic only after the graph behaviour is familiar.
- Validate: compare against a trusted library on random and adversarial sparse patterns.
15. Learning Progression: Beginner to Professional
- Beginner: convert a 0/1 matrix pattern into a bipartite graph and find a matching by hand.
- Intermediate: compute structural rank and trace alternating paths from unmatched vertices.
- Advanced: derive coarse DM regions and implement the fine decomposition of a balanced core.
- Professional: benchmark a sparse implementation, preserve symbolic structure across repeated solves, compare library permutation conventions, and test whether decomposition reduces downstream factorisation work.
16. Practice Problems
- Create a 5×7 sparse pattern with structural rank 5. Which columns must remain unmatched?
- Construct a square pattern with full structural rank but numerical rank one. What does that teach you?
- Take a bipartite graph with two different maximum matchings and trace the alternating path that transforms one into the other.
- Add one structural nonzero to an underdetermined component. Does the structural rank always increase? Explain.
- Generate random sparse matrices and compare your structural-rank calculation with SciPy.
- Use MATLAB
dmpermor HSL_MC79 on a block-structured sparse matrix and verify the returned boundaries. - Measure sparse LU or QR behaviour before and after a DM-style block permutation on a representative problem.
17. Sources and Further Reading
- MATLAB: dmperm — Dulmage–Mendelsohn decomposition.
- HSL_MC79: maximum matching and Dulmage–Mendelsohn decomposition for sparse matrices.
- Timothy A. Davis, Direct Methods for Sparse Linear Systems — fill-reducing orderings and DM decomposition.
- SciPy: maximum_bipartite_matching.
- SciPy: structural_rank.
- ACM/IEEE-CS CS2023: Algorithmic Foundations.
- Sentance, Waite & Kallia: PRIMM programming pedagogy.
- Margulieux, Morrison & Decker: subgoal-labelled worked examples in programming.
Final idea: Dulmage–Mendelsohn decomposition teaches a professional habit that reaches far beyond sparse matrices: before doing expensive numerical work, ask whether the structure has already told you what kind of problem you have. A pattern can contain a diagnosis long before arithmetic begins.
