MyraMath
Tutorial for /multifrontal solvers (part 1)

Overview

This tutorial covers the basic steps for using the direct solvers in /multifrontal to solve A*X=B when A is sparse and structurally symmetric. Unlike the dense case, sparse matrix decompositions can't generally be performed in-place due to fill-in (the creation of additional nonzeroes in the L and U factors). Careful reordering of A can greatly reduce fill-in and is a key step in efficient sparse direct solution.

After reordering comes a symbolic factorization step wherein the patterns of the L and U factors are tabulated along with predictions of memory and flop cost. If the need arises to solve multiple matrices with identical nonzero patterns and similar numerical properties, it is possible to precompute the reordering and symbolic factorization once, and then reuse it.

Numeric factorization is the most time consuming part of the direct solution process, and is internally multithreaded for improved performance. When numerical factorization is complete, the decomposed A can be used to solve for arbitrary/multiple right hand sides B with relatively little effort. This can be the chief advantage of using a sparse direct solver like those in /multifrontal.

Below are links to the sections of this page:

Reordering and Permutations

Reordering unknowns prior to sparse factorization can have a dramatic impact on the total storage and flop requirements. Multifrontal solvers (like all the ones in MyraMath) tend to perform best with nested dissection (ND) orderings. ND is a divide and conquer strategy in which a top-level "separator" of unknowns is identified, whose removal will split the remainder into two unconnected subgroups, "left" and "right". When the unknowns are reordered into (left, right, separator), no structural fill-in can propagate between the left and right groups. The algorithm then recurses, dissecting the left group further, dissecting the right group further, and so forth.

For Pattern's arising from structured problems (like 2D/3D Cartesian grids), ND is extremely easy to perform because the separator is always a line/plane of unknowns at the "middle" of the grid. For the more important case of general unstructured Pattern's, ND is more expensive and considerably harder to implement. MyraMath provides orderings for both cases, the 2D/3D structured cases are implemented by bisect2() and bisect3() (in sparse/laplacian2.h and sparse/laplacian3.h), while the unstructured case is implemented by reorder() (in multifrontal/symbolic/reorder.h).

The excerpt below (tutorial/multifrontal/reorder.cpp) applies both algorithms to a 7x7 structured grid.

7 
10 
11 #include <tests/myratest.h>
12 
13 #include <iostream>
14 
15 using namespace myra;
16 
17 ADD_TEST("multifrontal_reorder","[multifrontal]") // int main()
18  {
19  // Construct stencil for a 2D structured grid, visualize using PatternBuilder.
20  Pattern A = stencil2(7,7);
21  std::cout << "A = " << PatternBuilder(A) << std::endl;
22  // Reorder A using structured nested dissection, visualize.
23  Permutation P = bisect2(7,7);
24  std::cout << "A permuted by bisect2() = " << PatternBuilder(permute(P,A)) << std::endl;
25  // Reorder A using unstructured nested dissection, visualize.
26  Permutation Q = reorder(A);
27  std::cout << "A permuted by reorder() = " << PatternBuilder(permute(Q,A)) << std::endl;
28  }
Represents a Permutation matrix, used to reorder rows/columns/etc of various numeric containers...
Definition: Permutation.h:34
Builder class for a sparse nonzero pattern, used in reordering/symbolic analysis. ...
Returns elimination postorder.
Definition: syntax.dox:1
Range/Iterator types associated with Pattern.
Given a SparseMatrix A and permutations P and Q, returns P&#39;*A*Q.
Holds the nonzero pattern of a sparse matrix.
Definition: Pattern.h:55
Like Pattern, but easier to populate via insert()/erase() methods.
Definition: PatternBuilder.h:31
Container class for a sparse nonzero pattern, used in reordering/symbolic analysis.
Aggregates a (perm, iperm, swaps) triple into a vocabulary type.
Computes a fill-reducing Permutation for a structurally symmetric sparse A.
Helper routines for reordering/filling 2D structured grids. Used by many unit tests.
A = size 49 by 49 pattern:
[ x x - - - - - x - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ]
[ x x x - - - - - x - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ]
[ - x x x - - - - - x - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ]
[ - - x x x - - - - - x - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ]
[ - - - x x x - - - - - x - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ]
[ - - - - x x x - - - - - x - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ]
[ - - - - - x x - - - - - - x - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ]
[ x - - - - - - x x - - - - - x - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ]
[ - x - - - - - x x x - - - - - x - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ]
[ - - x - - - - - x x x - - - - - x - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ]
[ - - - x - - - - - x x x - - - - - x - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ]
[ - - - - x - - - - - x x x - - - - - x - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ]
[ - - - - - x - - - - - x x x - - - - - x - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ]
[ - - - - - - x - - - - - x x - - - - - - x - - - - - - - - - - - - - - - - - - - - - - - - - - - - ]
[ - - - - - - - x - - - - - - x x - - - - - x - - - - - - - - - - - - - - - - - - - - - - - - - - - ]
[ - - - - - - - - x - - - - - x x x - - - - - x - - - - - - - - - - - - - - - - - - - - - - - - - - ]
[ - - - - - - - - - x - - - - - x x x - - - - - x - - - - - - - - - - - - - - - - - - - - - - - - - ]
[ - - - - - - - - - - x - - - - - x x x - - - - - x - - - - - - - - - - - - - - - - - - - - - - - - ]
[ - - - - - - - - - - - x - - - - - x x x - - - - - x - - - - - - - - - - - - - - - - - - - - - - - ]
[ - - - - - - - - - - - - x - - - - - x x x - - - - - x - - - - - - - - - - - - - - - - - - - - - - ]
[ - - - - - - - - - - - - - x - - - - - x x - - - - - - x - - - - - - - - - - - - - - - - - - - - - ]
[ - - - - - - - - - - - - - - x - - - - - - x x - - - - - x - - - - - - - - - - - - - - - - - - - - ]
[ - - - - - - - - - - - - - - - x - - - - - x x x - - - - - x - - - - - - - - - - - - - - - - - - - ]
[ - - - - - - - - - - - - - - - - x - - - - - x x x - - - - - x - - - - - - - - - - - - - - - - - - ]
[ - - - - - - - - - - - - - - - - - x - - - - - x x x - - - - - x - - - - - - - - - - - - - - - - - ]
[ - - - - - - - - - - - - - - - - - - x - - - - - x x x - - - - - x - - - - - - - - - - - - - - - - ]
[ - - - - - - - - - - - - - - - - - - - x - - - - - x x x - - - - - x - - - - - - - - - - - - - - - ]
[ - - - - - - - - - - - - - - - - - - - - x - - - - - x x - - - - - - x - - - - - - - - - - - - - - ]
[ - - - - - - - - - - - - - - - - - - - - - x - - - - - - x x - - - - - x - - - - - - - - - - - - - ]
[ - - - - - - - - - - - - - - - - - - - - - - x - - - - - x x x - - - - - x - - - - - - - - - - - - ]
[ - - - - - - - - - - - - - - - - - - - - - - - x - - - - - x x x - - - - - x - - - - - - - - - - - ]
[ - - - - - - - - - - - - - - - - - - - - - - - - x - - - - - x x x - - - - - x - - - - - - - - - - ]
[ - - - - - - - - - - - - - - - - - - - - - - - - - x - - - - - x x x - - - - - x - - - - - - - - - ]
[ - - - - - - - - - - - - - - - - - - - - - - - - - - x - - - - - x x x - - - - - x - - - - - - - - ]
[ - - - - - - - - - - - - - - - - - - - - - - - - - - - x - - - - - x x - - - - - - x - - - - - - - ]
[ - - - - - - - - - - - - - - - - - - - - - - - - - - - - x - - - - - - x x - - - - - x - - - - - - ]
[ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - x - - - - - x x x - - - - - x - - - - - ]
[ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - x - - - - - x x x - - - - - x - - - - ]
[ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - x - - - - - x x x - - - - - x - - - ]
[ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - x - - - - - x x x - - - - - x - - ]
[ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - x - - - - - x x x - - - - - x - ]
[ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - x - - - - - x x - - - - - - x ]
[ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - x - - - - - - x x - - - - - ]
[ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - x - - - - - x x x - - - - ]
[ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - x - - - - - x x x - - - ]
[ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - x - - - - - x x x - - ]
[ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - x - - - - - x x x - ]
[ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - x - - - - - x x x ]
[ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - x - - - - - x x ]
A permuted by bisect2() = size 49 by 49 pattern:
[ x - x - - - x - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ]
[ - x x - - - - - x - - - - - - - - - x - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ]
[ x x x - - - - x - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ]
[ - - - x - x x - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - x - - - - - - ]
[ - - - - x x - - x - - - - - - - - - - - x - - - - - - - - - - - - - - - - - - - - - - - x - - - - ]
[ - - - x x x - x - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - x - - - - - ]
[ x - - x - - x x - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ]
[ - - x - - x x x x - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ]
[ - x - - x - - x x - - - - - - - - - - x - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ]
[ - - - - - - - - - x - x - - - x - - x - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ]
[ - - - - - - - - - - x x - - - - - x - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ]
[ - - - - - - - - - x x x - - - - x - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ]
[ - - - - - - - - - - - - x - x x - - - - x - - - - - - - - - - - - - - - - - - - - - - - - - x - - ]
[ - - - - - - - - - - - - - x x - - x - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - x ]
[ - - - - - - - - - - - - x x x - x - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - x - ]
[ - - - - - - - - - x - - x - - x x - - x - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ]
[ - - - - - - - - - - - x - - x x x x - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ]
[ - - - - - - - - - - x - - x - - x x - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ]
[ - x - - - - - - - x - - - - - - - - x x - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ]
[ - - - - - - - - x - - - - - - x - - x x x - - - - - - - - - - - - - - - - - - - - - - - - - - - - ]
[ - - - - x - - - - - - - x - - - - - - x x - - - - - - - - - - - - - - - - - - - - - - - - x - - - ]
[ - - - - - - - - - - - - - - - - - - - - - x - x - - - x - - - - - - - - - - - - - - x - - - - - - ]
[ - - - - - - - - - - - - - - - - - - - - - - x x - - - - - x - - - - - - - - - x - - - - x - - - - ]
[ - - - - - - - - - - - - - - - - - - - - - x x x - - - - x - - - - - - - - - - - - - - x - - - - - ]
[ - - - - - - - - - - - - - - - - - - - - - - - - x - x x - - - - - - - - - - - - - - - - - - - - - ]
[ - - - - - - - - - - - - - - - - - - - - - - - - - x x - - x - - - - - - - - - - - x - - - - - - - ]
[ - - - - - - - - - - - - - - - - - - - - - - - - x x x - x - - - - - - - - - - - - - - - - - - - - ]
[ - - - - - - - - - - - - - - - - - - - - - x - - x - - x x - - - - - - - - - - - - - - - - - - - - ]
[ - - - - - - - - - - - - - - - - - - - - - - - x - - x x x x - - - - - - - - - - - - - - - - - - - ]
[ - - - - - - - - - - - - - - - - - - - - - - x - - x - - x x - - - - - - - - - - x - - - - - - - - ]
[ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - x - x - - - x - - x - - - - - - x - - ]
[ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - x x - - - - - x - - - - - - - - - x ]
[ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - x x x - - - - x - - - - - - - - - x - ]
[ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - x - x x - - - - x - - - - - - - ]
[ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - x x - - x - - - - - - - - - - ]
[ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - x x x - x - - - - - - - - - - - ]
[ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - x - - x - - x x - - x - - - - - - - - ]
[ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - x - - x x x x - - - - - - - - - - ]
[ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - x - - x - - x x - - - - - - - - - - ]
[ - - - - - - - - - - - - - - - - - - - - - - x - - - - - - - x - - - - - - - - x x - - - - x - - - ]
[ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - x - - - - - - x - - x x x - - - - - - - ]
[ - - - - - - - - - - - - - - - - - - - - - - - - - x - - - - - - - x - - - - - - x x - - - - - - - ]
[ - - - x - - - - - - - - - - - - - - - - - x - - - - - - - - - - - - - - - - - - - - x x - - - - - ]
[ - - - - - x - - - - - - - - - - - - - - - - - x - - - - - - - - - - - - - - - - - - x x x - - - - ]
[ - - - - x - - - - - - - - - - - - - - - - - x - - - - - - - - - - - - - - - - - - - - x x x - - - ]
[ - - - - - - - - - - - - - - - - - - - - x - - - - - - - - - - - - - - - - - - x - - - - x x x - - ]
[ - - - - - - - - - - - - x - - - - - - - - - - - - - - - - - x - - - - - - - - - - - - - - x x x - ]
[ - - - - - - - - - - - - - - x - - - - - - - - - - - - - - - - - x - - - - - - - - - - - - - x x x ]
[ - - - - - - - - - - - - - x - - - - - - - - - - - - - - - - - x - - - - - - - - - - - - - - - x x ]
A permuted by reorder() = size 49 by 49 pattern:
[ x x - - - - - - - - x - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ]
[ x x - - - - - - - - - x x - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ]
[ - - x x - - - - - - x - - - - - - - - - - - - - x - - - - - - - - - - - - - - - - - - - - - - - - ]
[ - - x x - - - - - x - x - - - - - - - - - - - - - x - - - - - - - - - - - - - - - - - - - - - - - ]
[ - - - - x x - - - x - x x - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ]
[ - - - - x x - - x - - - - x - - - - - - - - - - - - - - - - - - - - - - - - - - - - - x - - - - - ]
[ - - - - - - x x - x - - - - - - - - - - - - - - - x x - - - - - - - - - - - - - - - - - - - - - - ]
[ - - - - - - x x x - - - - - - - - - - - - - - - - - - x - - - - - - - - - - - - - - - - - x - - - ]
[ - - - - - x - x x x - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - x - - - - ]
[ - - - x x - x - x x - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ]
[ x - x - - - - - - - x x - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ]
[ - x - x x - - - - - x x - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ]
[ - x - - x - - - - - - - x x - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ]
[ - - - - - x - - - - - - x x - - - - - - - - - - - - - - - - - - - - - - - - - - - - x - - - - - - ]
[ - - - - - - - - - - - - - - x - x - - - - x - - - x x - - - - - - - - - - - - - - - - - - - - - - ]
[ - - - - - - - - - - - - - - - x - x - - x - - - - - - x - - - - - - - - - - - - - - - - - - - x - ]
[ - - - - - - - - - - - - - - x - x x x - - - x - - - - - - - - - - - - - - - - - - - - - - - - - - ]
[ - - - - - - - - - - - - - - - x x x - x - - - - - - x - - - - - - - - - - - - - - - - - - - - - - ]
[ - - - - - - - - - - - - - - - - x - x x - - - x - - - - - - - - - - - - - - - - - - - - - - - - - ]
[ - - - - - - - - - - - - - - - - - x x x x - - - - - - - - - - - - - - - - - - - - - - - - - - - - ]
[ - - - - - - - - - - - - - - - x - - - x x - - - - - - - - - - - - - - - - - - - - - - - - - - - x ]
[ - - - - - - - - - - - - - - x - - - - - - x x - x - - - - - - - - - - - - - - - - - - - - - - - - ]
[ - - - - - - - - - - - - - - - - x - - - - x x x - - - - - - - - - - - - - - - - - - - - - - - - - ]
[ - - - - - - - - - - - - - - - - - - x - - - x x - - - - - - - - - - - - - - - - - - - - - - - - - ]
[ - - x - - - - - - - - - - - - - - - - - - x - - x x - - - - - - - - - - - - - - - - - - - - - - - ]
[ - - - x - - x - - - - - - - x - - - - - - - - - x x - - - - - - - - - - - - - - - - - - - - - - - ]
[ - - - - - - x - - - - - - - x - - x - - - - - - - - x x - - - - - - - - - - - - - - - - - - - - - ]
[ - - - - - - - x - - - - - - - x - - - - - - - - - - x x - - - - - - - - - - - - - - - - - - x - - ]
[ - - - - - - - - - - - - - - - - - - - - - - - - - - - - x - x - x - - - - - - - - - - - - - - - - ]
[ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - x - x - - - - - - - - x x - - - - - - - ]
[ - - - - - - - - - - - - - - - - - - - - - - - - - - - - x - x x - x - - - - - - - - - - - - - - - ]
[ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - x x x - - x - - - - - - - - - - - - - - ]
[ - - - - - - - - - - - - - - - - - - - - - - - - - - - - x - - - x x - - - - - - - - x - - - - - - ]
[ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - x - x x x - - - - - - - - x - - - - - ]
[ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - x - x x - - - - - x - - - x - - - - ]
[ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - x - - - x x x - - - - x - - ]
[ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - x - x x - - - - - - - - x ]
[ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - x x x - x - - - - - - - ]
[ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - x x x - - - - - - - - - - ]
[ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - x x x - x - - - - - - - x - ]
[ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - x - - - - x x - - - - x - - - - x - - - ]
[ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - x - - - - - x - x - - - x - - - - - - - ]
[ - - - - - - - - - - - - - x - - - - - - - - - - - - - - - - - - x - - - - - - - - - x x - - - - - ]
[ - - - - - x - - - - - - - - - - - - - - - - - - - - - - - - - - - x - - - - - - - - x x x - - - - ]
[ - - - - - - - - x - - - - - - - - - - - - - - - - - - - - - - - - - x - - - - - - - - x x x - - - ]
[ - - - - - - - x - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - x - - - x x x - - ]
[ - - - - - - - - - - - - - - - - - - - - - - - - - - - x - - - - - - - x - - - - - - - - - x x x - ]
[ - - - - - - - - - - - - - - - x - - - - - - - - - - - - - - - - - - - - - - - x - - - - - - x x x ]
[ - - - - - - - - - - - - - - - - - - - - x - - - - - - - - - - - - - - - x - - - - - - - - - - x x ]

(However, see Sidenote 1)

For sake of completeness, there are other reordering algorithms present in MyraMath that are based on other (non-ND) principles. There are two variants of the minimum-degree (MD) algorithm: amd() (approximate-MD) and mmd() (minimum-MD). When reordering/solving sparse systems that arose from a 2D/3D discretization of a partial differential equation, these algorithms are typically beaten by nested dissection. But, they are sometimes useful for other/non-geometrical sparse systems (analysis of circuit networks or unstructured graph laplacians, for instance). See multifrontal/symbolic/amd.h and multifrontal/symbolic/mmd.h for details.

The output of the bisect() and reorder() routines is a Permutation, which should be submitted to downstream symbolic/numeric factorization stages. It is anticipated that end users might wish to inject their own ordering, perhaps by calling into other third party reordering packages like Metis, AMD or Scotch. In that case, you can construct a Permutation from their output, a (permuted) index vector. See Permutation::from_perm() and Permutation::from_iperm() for details.

Symbolic Factorization, the AssemblyTree

In an effort to streamline the numerical factorization and backsolution phases, sparse direct solvers perform extensive symbolic analysis that (i) explicitly tabulates all the fill-in for the L and U factors (ii) aggregates unknowns with similar connectivity into "supernodes" for improved BLAS3 utilization and (iii) performs dependency analysis for the purpose of exposing parallelism. In MyraMath, the symbolic factorization is encapsulated into a data structure called the AssemblyTree. An AssemblyTree is constructed from a Pattern and a Permutation, typically the output of bisect2()/bisect3() or reorder(). The code excerpt below (tutorial/multifrontal/symbolic.cpp) shows the workflow to produce an AssemblyTree. Alternatively, you can access the AssemblyTree of an existing factorization (to reuse on a second A with the same Pattern and similar numerical properties).

7 
10 
11 #include <tests/myratest.h>
12 
13 #include <cmath>
14 #include <iostream>
15 
16 using namespace myra;
17 
18 ADD_TEST("multifrontal_symbolic","[multifrontal]") // int main()
19  {
20  // Analyze structured 3D grids of increasing size, d by d by d
21  int N[7] = {1000,2000,4000,8000,16000,32000,64000};
22  for (int n : N)
23  {
24  int d = static_cast<int>(std::pow(n,1.0/3.0));
25  // Construct SparseMatrix A
26  SparseMatrix<double> A = laplacian3<double>(d,d,d);
27  // Compute fill reducing reordering P
28  Permutation P = bisect3(d,d,d);
29  // Perform symbolic factorization
30  AssemblyTree atree(A.pattern(),P);
31  // Report flop count.
32  std::cout << P.size() << " unknowns -> " << atree.n_work_llt() << " flops" << std::endl;
33  }
34  }
Represents a Permutation matrix, used to reorder rows/columns/etc of various numeric containers...
Definition: Permutation.h:34
Symbolic analysis data structure for all multifrontal solvers.
Definition: AssemblyTree.h:38
General purpose compressed-sparse-column (CSC) container.
Definition: syntax.dox:1
PatternRange pattern() const
Returns the nonzero Pattern over all of A(:,:)
Definition: SparseMatrix.cpp:221
Describes data layout and job dependencies for symmetric-pattern multifrontal solvers.
Helper routines for reordering/filling 3D structured grids. Used by many unit tests.
Range/Iterator types associated with Pattern.
Container class for a sparse nonzero pattern, used in reordering/symbolic analysis.
Aggregates a (perm, iperm, swaps) triple into a vocabulary type.
int size() const
Returns size of underlying system A.
Definition: AssemblyTree.cpp:1018
Computes a fill-reducing Permutation for a structurally symmetric sparse A.
Stores an IxJ matrix A in compressed sparse column format.
Definition: bothcat.h:23
Range/Iterator types associated with SparseMatrix.
729 unknowns -> 2799981 flops
1728 unknowns -> 18817132 flops
3375 unknowns -> 79766835 flops
6859 unknowns -> 146058595 flops
15625 unknowns -> 823869935 flops
29791 unknowns -> 3142543645 flops
59319 unknowns -> 10411697407 flops

AssemblyTree is primarily for internal use. The only member functions of any interest to an end-user are probably .n_words() and .n_work(), which return space and time cost estimates for A=L*L' or A=L*U. For instance, the output of this example program indicates that the cost for direct factorization of a sparse matrix arising from discretizing PDE in three dimensions scales with the unknown count n as O(n^2). (Since each time the problem size doubled, the flop count quadrupled).

Solver Classes and Options

There are currently six different solver classes inside /multifrontal, each is applicable to a different type of linear A*X=B system:

Generally speaking, solvers higher on this list are simpler, more efficient or more robust than solvers lower on this list. Pick the simplest solver that is still suitable for your A. Note that MyraMath currently offers little functionality for systems with nonsymmetric nonzero patterns. For such systems, try using SuperLU or UMPACK instead.

Constructing any solver requires the input SparseMatrix A, and you can also optionally specify a Permutation for reordering (from a third party package, for example) or a precomputed AssemblyTree (when solving multiple A's with the same Pattern, for example). The code excerpt below illustrates these cases (tutorial/multifrontal/solver.cpp):

2 
9 
12 
14 
15 #include <tests/myratest.h>
16 
17 #include <iostream>
18 
19 using namespace myra;
20 
21 namespace {
22 
23 // Useful typedefs.
24 typedef SparseRCholeskySolver<double> Solver;
25 typedef typename Solver::Options Options;
26 
27 // Constructs a Solver from just a SparseMatrix A, uses internal reorder()'ing routine.
28 void example3a()
29  {
30  SparseMatrix<double> A = laplacian3<double>(10,10,10);
31  Solver solver(A);
32  }
33 
34 // Constructs a Solver from a SparseMatrix A and the natural ordering P = {0,1,2..999}
35 void example3b()
36  {
37  SparseMatrix<double> A = laplacian3<double>(10,10,10);
39  Solver solver(A,P);
40  }
41 
42 // Constructs a Solver from a SparseMatrix A and a precomputed AssemblyTree based on bisect3() ordering.
43 void example3c()
44  {
45  SparseMatrix<double> A = laplacian3<double>(10,10,10);
46  Permutation P = bisect3(10,10,10);
47  AssemblyTree tree(A.pattern(),P);
48  Solver solver(A,tree);
49  }
50 
51 // Constructs a Solver from just a SparseMatrix A, passes a ProgressMeter through options.
52 void example3d()
53  {
54  SparseMatrix<double> A = laplacian3<double>(30,30,30);
55  ProgressMeter progress = make_TextProgressMeter();
56  Solver solver(A, Options::create().set_progress(progress));
57  }
58 
59 } // namespace
60 
61 ADD_TEST("multifrontal_solver","[multifrontal]") // int main()
62  {
63  example3a();
64  example3b();
65  example3c();
66  example3d();
67  }
Displays a text-based ProgressMeter on console output.
Represents a Permutation matrix, used to reorder rows/columns/etc of various numeric containers...
Definition: Permutation.h:34
Symbolic analysis data structure for all multifrontal solvers.
Definition: AssemblyTree.h:38
static Permutation identity(int N)
Generates an identity Matrix of specified size.
Definition: Permutation.cpp:181
General purpose compressed-sparse-column (CSC) container.
Definition: syntax.dox:1
Interface for measuring progress via callbacks. Wraps an underlying polymorphic ProgressMeterBase.
Definition: ProgressMeter.h:55
PatternRange pattern() const
Returns the nonzero Pattern over all of A(:,:)
Definition: SparseMatrix.cpp:221
Describes data layout and job dependencies for symmetric-pattern multifrontal solvers.
Returns a vector of int&#39;s, over [min,max)
Helper routines for reordering/filling 3D structured grids. Used by many unit tests.
Range/Iterator types associated with Pattern.
Sparse direct solver suitable for real symmetric positive definite systems.
Container class for a sparse nonzero pattern, used in reordering/symbolic analysis.
Aggregates a (perm, iperm, swaps) triple into a vocabulary type.
Sparse direct solver suitable for real symmetric positive definite systems.
Definition: SparseRCholeskySolver.h:61
Stores an IxJ matrix A in compressed sparse column format.
Definition: bothcat.h:23
Range/Iterator types associated with SparseMatrix.
Sparse A = L*L' factor(27000 unknowns, work = 3550667924):
[----------------------------------------------------------------] (285 ms)

A variety of control and tuning parameters can be injected into a solver constructor call through its trailing (and defaulted) multifrontal::Options pack. In the code excerpt above, example3d() uses this to pass in a callback function for progress visualization. For further details, see Multifrontal Options.

Backsolution

Each of the solver classes listed above offers a general purpose .solve() method for solving op(A)*X=B or X*op(A)=B. Regardless of the op or side parameters, .solve() always has in-place semantics, which means you pass in B and the routine overwrites it with X. Below, tutorial/multifrontal/solve.cpp shows how to use .solve():

4 
8 
10 
11 #include <tests/myratest.h>
12 
13 #include <iostream>
14 
15 using namespace myra;
16 
17 // Solves A*x = b
18 //
19 // A * x = b
20 //
21 // [ 3 - 0 0 - 0 0 0 0 0 0 0 0 0 0 0 ] [ 1 ] [ -4 ]
22 // [ - 4 - 0 0 - 0 0 0 0 0 0 0 0 0 0 ] [ 2 ] [ -2 ]
23 // [ 0 - 4 - 0 0 - 0 0 0 0 0 0 0 0 0 ] [ 3 ] [ -1 ]
24 // [ 0 0 - 3 0 0 0 - 0 0 0 0 0 0 0 0 ] [ 4 ] [ 1 ]
25 // [ - 0 0 0 4 - 0 0 - 0 0 0 0 0 0 0 ] [ 5 ] [ 4 ]
26 // [ 0 - 0 0 - 5 - 0 0 - 0 0 0 0 0 0 ] [ 6 ] [ 6 ]
27 // [ 0 0 - 0 0 - 5 - 0 0 - 0 0 0 0 0 ] [ 7 ] [ 7 ]
28 // [ 0 0 0 - 0 0 - 4 0 0 0 - 0 0 0 0 ] * [ 8 ] = [ 9 ]
29 // [ 0 0 0 0 - 0 0 0 4 - 0 0 - 0 0 0 ] [ 9 ] [ 8 ]
30 // [ 0 0 0 0 0 - 0 0 - 5 - 0 0 - 0 0 ] [ 10 ] [ 10 ]
31 // [ 0 0 0 0 0 0 - 0 0 - 5 - 0 0 - 0 ] [ 11 ] [ 11 ]
32 // [ 0 0 0 0 0 0 0 - 0 0 - 4 0 0 0 - ] [ 12 ] [ 13 ]
33 // [ 0 0 0 0 0 0 0 0 - 0 0 0 3 - 0 0 ] [ 13 ] [ 16 ]
34 // [ 0 0 0 0 0 0 0 0 0 - 0 0 - 4 - 0 ] [ 14 ] [ 18 ]
35 // [ 0 0 0 0 0 0 0 0 0 0 - 0 0 - 4 - ] [ 15 ] [ 19 ]
36 // [ 0 0 0 0 0 0 0 0 0 0 0 - 0 0 - 3 ] [ 16 ] [ 21 ]
37 
38 ADD_TEST("multifrontal_solve","[multifrontal]") // int main()
39  {
40  // Construct solver for A.
41  SparseMatrix<double> A = laplacian2<double>(4,4);
43  // Construct b.
44  auto x = Vector<double>::fill({1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16});
45  auto b = Vector<double>::fill({-4,-2,-1,1,4,6,7,9,8,10,11,13,16,18,19,21});
46  std::cout << "A = " << A.make_Matrix() << std::endl;
47  std::cout << "x = " << x << std::endl;
48  std::cout << "b = A*x = " << b << std::endl;
49  // Solve A*x = b, overwriting b with x.
50  solver.solve(b.column());
51  std::cout << "A\\b = " << b << std::endl;
52  std::cout << "euclidean(A\\b-x) = " << euclidean(b-x) << std::endl;
53  }
static Vector< Number > fill(int N, Number c)
Generates a Vector of specified size filled with constant c.
Definition: Vector.cpp:288
Routines for computing euclidean norm of a Vector/VectorRange, or normalizing a Vector/VectorRange to...
General purpose compressed-sparse-column (CSC) container.
Definition: syntax.dox:1
General purpose dense matrix container, O(i*j) storage.
Sparse direct solver suitable for real symmetric positive definite systems.
Container for either a column vector or row vector (depends upon the usage context) ...
CMatrixRange< Number > column() const
Returns an Nx1 column-shaped MatrixRange over all of *this.
Definition: Vector.cpp:152
Sparse direct solver suitable for real symmetric positive definite systems.
Definition: SparseRCholeskySolver.h:61
Stores an IxJ matrix A in compressed sparse column format.
Definition: bothcat.h:23
Helper routines for reordering/filling 2D structured grids. Used by many unit tests.
Range/Iterator types associated with SparseMatrix.
Matrix< Number > make_Matrix() const
Accumulates *this onto a Matrix<Number>.
Definition: SparseMatrix.cpp:581
A = size 16 by 16 Matrix of double:
[ 3 -1 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 ]
[ -1 4 -1 0 0 -1 0 0 0 0 0 0 0 0 0 0 ]
[ 0 -1 4 -1 0 0 -1 0 0 0 0 0 0 0 0 0 ]
[ 0 0 -1 3 0 0 0 -1 0 0 0 0 0 0 0 0 ]
[ -1 0 0 0 4 -1 0 0 -1 0 0 0 0 0 0 0 ]
[ 0 -1 0 0 -1 5 -1 0 0 -1 0 0 0 0 0 0 ]
[ 0 0 -1 0 0 -1 5 -1 0 0 -1 0 0 0 0 0 ]
[ 0 0 0 -1 0 0 -1 4 0 0 0 -1 0 0 0 0 ]
[ 0 0 0 0 -1 0 0 0 4 -1 0 0 -1 0 0 0 ]
[ 0 0 0 0 0 -1 0 0 -1 5 -1 0 0 -1 0 0 ]
[ 0 0 0 0 0 0 -1 0 0 -1 5 -1 0 0 -1 0 ]
[ 0 0 0 0 0 0 0 -1 0 0 -1 4 0 0 0 -1 ]
[ 0 0 0 0 0 0 0 0 -1 0 0 0 3 -1 0 0 ]
[ 0 0 0 0 0 0 0 0 0 -1 0 0 -1 4 -1 0 ]
[ 0 0 0 0 0 0 0 0 0 0 -1 0 0 -1 4 -1 ]
[ 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 -1 3 ]
x = size 16 Vector of double:
[ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 ]
b = A*x = size 16 Vector of double:
[ -4 -2 -1 1 4 6 7 9 8 10 11 13 16 18 19 21 ]
A\b = size 16 Vector of double:
[ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 ]
euclidean(A\b-x) = 7.11236e-15

Generally speaking, backsolution exhibits poorer thread-parallel scalability than factorization, so .solve() runs with only a single thread by default. This can be overridden through Options, but appreciable speedup should only be expected when the number of right hand sides is comparable to the internal blocksize of the solver itself (a few dozen). At this point, the algorithm crosses over from BLAS2 dominated (memory bound) to BLAS3 dominated (compute bound).

Appendix: Working with external data.

External data can be injected into these A*X=B solvers by using a SparseMatrixRange to wrap around the external A stored in CSC format, and a MatrixRange to wrap around the external B stored in column major format. The desired solution X will overwrite B. The example code below (tutorial/multifrontal/external1.cpp) solves the same system as before, but uses raw C-arrays as mock "external" data:

4 
8 
10 
11 #include <tests/myratest.h>
12 
13 #include <iostream>
14 
15 using namespace myra;
16 
17 // Solves A*x = b
18 //
19 // A * x = b
20 //
21 // [ 3 - 0 0 - 0 0 0 0 0 0 0 0 0 0 0 ] [ 1 ] [ -4 ]
22 // [ - 4 - 0 0 - 0 0 0 0 0 0 0 0 0 0 ] [ 2 ] [ -2 ]
23 // [ 0 - 4 - 0 0 - 0 0 0 0 0 0 0 0 0 ] [ 3 ] [ -1 ]
24 // [ 0 0 - 3 0 0 0 - 0 0 0 0 0 0 0 0 ] [ 4 ] [ 1 ]
25 // [ - 0 0 0 4 - 0 0 - 0 0 0 0 0 0 0 ] [ 5 ] [ 4 ]
26 // [ 0 - 0 0 - 5 - 0 0 - 0 0 0 0 0 0 ] [ 6 ] [ 6 ]
27 // [ 0 0 - 0 0 - 5 - 0 0 - 0 0 0 0 0 ] [ 7 ] [ 7 ]
28 // [ 0 0 0 - 0 0 - 4 0 0 0 - 0 0 0 0 ] * [ 8 ] = [ 9 ]
29 // [ 0 0 0 0 - 0 0 0 4 - 0 0 - 0 0 0 ] [ 9 ] [ 8 ]
30 // [ 0 0 0 0 0 - 0 0 - 5 - 0 0 - 0 0 ] [ 10 ] [ 10 ]
31 // [ 0 0 0 0 0 0 - 0 0 - 5 - 0 0 - 0 ] [ 11 ] [ 11 ]
32 // [ 0 0 0 0 0 0 0 - 0 0 - 4 0 0 0 - ] [ 12 ] [ 13 ]
33 // [ 0 0 0 0 0 0 0 0 - 0 0 0 3 - 0 0 ] [ 13 ] [ 16 ]
34 // [ 0 0 0 0 0 0 0 0 0 - 0 0 - 4 - 0 ] [ 14 ] [ 18 ]
35 // [ 0 0 0 0 0 0 0 0 0 0 - 0 0 - 4 - ] [ 15 ] [ 19 ]
36 // [ 0 0 0 0 0 0 0 0 0 0 0 - 0 0 - 3 ] [ 16 ] [ 21 ]
37 
38 ADD_TEST("multifrontal_external1","[multifrontal]") // int main()
39  {
40  // Encoding A in compressed sparse column (CSC) format.
41  int A_strides[17] = {0,3,7,11,14,18,23,28,32,36,41,46,50,53,57,61,64};
42  int A_indices[64] = {0,1,4,0,1,2,5,1,2,3,6,2,3,7,0,4,5,8,1,4,5,6,9,2,5,
43  6,7,10,3,6,7,11,4,8,9,12,5,8,9,10,13,6,9,10,11,14,
44  7,10,11,15,8,12,13,9,12,13,14,10,13,14,15,11,14,15};
45  double A_values[64] = {3,-1,-1,-1,4,-1,-1,-1,4,-1,-1,-1,3,-1,-1,4,-1,-1,
46  -1,-1,5,-1,-1,-1,-1,5,-1,-1,-1,-1,4,-1,-1,4,-1,-1,
47  -1,-1,5,-1,-1,-1,-1,5,-1,-1,-1,-1,4,-1,-1,3,-1,-1,
48  -1,4,-1,-1,-1,4,-1,-1,-1,3};
49  SparseMatrixRange<double> A(A_strides,A_indices,A_values,16,16);
50  // Construct solver for A.
52  // Encoding b/x as column vectors.
53  double x_values[16] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16};
54  double b_values[16] = {-4,-2,-1,1,4,6,7,9,8,10,11,13,16,18,19,21};
55  VectorRange<double> x(x_values,16);
56  VectorRange<double> b(b_values,16);
57  std::cout << "A = " << A.make_Matrix() << std::endl;
58  std::cout << "x = " << x << std::endl;
59  std::cout << "b = A*x = " << b << std::endl;
60  // Solve A*x = b, overwriting b with x.
61  solver.solve(b.column());
62  std::cout << "A\\b = " << b << std::endl;
63  std::cout << "euclidean(A\\b-x) = " << euclidean(b-x) << std::endl;
64  }
Represents a mutable SparseMatrixRange.
Definition: conjugate.h:21
Routines for computing euclidean norm of a Vector/VectorRange, or normalizing a Vector/VectorRange to...
Represents a mutable VectorRange.
Definition: axpy.h:21
General purpose compressed-sparse-column (CSC) container.
Definition: syntax.dox:1
General purpose dense matrix container, O(i*j) storage.
Sparse direct solver suitable for real symmetric positive definite systems.
Container for either a column vector or row vector (depends upon the usage context) ...
CMatrixRange< Number > column() const
Returns an Nx1 column-shaped MatrixRange over all of *this.
Definition: Vector.cpp:152
Sparse direct solver suitable for real symmetric positive definite systems.
Definition: SparseRCholeskySolver.h:61
Helper routines for reordering/filling 2D structured grids. Used by many unit tests.
Range/Iterator types associated with SparseMatrix.
Matrix< Number > make_Matrix() const
Accumulates *this onto a Matrix<Number>.
Definition: SparseMatrix.cpp:581
A = size 16 by 16 Matrix of double:
[ 3 -1 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 ]
[ -1 4 -1 0 0 -1 0 0 0 0 0 0 0 0 0 0 ]
[ 0 -1 4 -1 0 0 -1 0 0 0 0 0 0 0 0 0 ]
[ 0 0 -1 3 0 0 0 -1 0 0 0 0 0 0 0 0 ]
[ -1 0 0 0 4 -1 0 0 -1 0 0 0 0 0 0 0 ]
[ 0 -1 0 0 -1 5 -1 0 0 -1 0 0 0 0 0 0 ]
[ 0 0 -1 0 0 -1 5 -1 0 0 -1 0 0 0 0 0 ]
[ 0 0 0 -1 0 0 -1 4 0 0 0 -1 0 0 0 0 ]
[ 0 0 0 0 -1 0 0 0 4 -1 0 0 -1 0 0 0 ]
[ 0 0 0 0 0 -1 0 0 -1 5 -1 0 0 -1 0 0 ]
[ 0 0 0 0 0 0 -1 0 0 -1 5 -1 0 0 -1 0 ]
[ 0 0 0 0 0 0 0 -1 0 0 -1 4 0 0 0 -1 ]
[ 0 0 0 0 0 0 0 0 -1 0 0 0 3 -1 0 0 ]
[ 0 0 0 0 0 0 0 0 0 -1 0 0 -1 4 -1 0 ]
[ 0 0 0 0 0 0 0 0 0 0 -1 0 0 -1 4 -1 ]
[ 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 -1 3 ]
x = size 16 Vector of double:
[ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 ]
b = A*x = size 16 Vector of double:
[ -4 -2 -1 1 4 6 7 9 8 10 11 13 16 18 19 21 ]
A\b = size 16 Vector of double:
[ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 ]
euclidean(A\b-x) = 7.11236e-15

Continue to Tutorial for /multifrontal solvers (part 2), or go back to API Tutorials