I decided to do the test I proposed in a comment myself. It is known that LinearSolve[]
, when applied to just a matrix, generates a LinearSolveFunction[]
that internally stores the LU decomposition of a matrix. I feel that it would be more accurate for timing purposes to decouple the decomposition and backsubstitution phases, and take the timings only on the backsubstitution.
With that,
(* LU-decomposed matrices *)
lstab = Table[LinearSolve[RandomVariate[NormalDistribution[], {k, k}]],
{k, 100, 1000, 100}];
(* random vectors with matching dimensions *)
vecs = Table[RandomVariate[NormalDistribution[], k], {k, 100, 1000, 100}];
(* extract and transpose upper triangular factors for lower triangular example *)
tritab = Composition[LinearSolve, Transpose] /@ Through[lstab["getU"]];
(* ...and, timing! *)
timeFull = Table[{100 n, RepeatedTiming[lstab[[n]] @ vecs[[n]], .1][[1]]}, {n, 10}];
timeTri = Table[{100 n, RepeatedTiming[tritab[[n]] @ vecs[[n]], .1][[1]]}, {n, 10}];
ListLinePlot[{Legended[timeTri, "lower triangular"],
Legended[timeFull, "full matrix"]},
PlotMarkers -> Automatic, PlotRange -> All]

At the very least, we can guess that the backsubstitution behind the scenes is faster in the lower triangular case than in the full case, since the latter has to do two of them.
As a further comparison, I tried comparing the use of LinearSolve[]
on a lower triangular matrix against a direct call to the internal BLAS function *TRSV
:
(* lower triangular matrices *)
trimat = Transpose /@ Through[lstab["getU"]];
(* timing BLAS calls *)
timeBLAS = Table[{100 n, RepeatedTiming[
Block[{mat = trimat[[n]], x = vecs[[n]]},
LinearAlgebra`BLAS`TRSV["L", "N", "N", mat, x]], .1][[1]]},
{n, 10}];
(* timing LinearSolve[] calls *)
timeTri = Table[{100 n, RepeatedTiming[tritab[[n]]@vecs[[n]], .1][[1]]}, {n, 10}];
ListLinePlot[{Legended[timeTri, "LinearSolve"],
Legended[timeBLAS, "BLAS"]},
PlotMarkers -> Automatic, PlotRange -> All]
![LinearSolve[] versus BLAS](https://i.stack.imgur.com/UVLSw.png)
If the overhead of LinearSolve[]
is a concern, I suppose a direct BLAS call can be used instead.
LUBackSubstitution[]
: it used to be documented, but it was quietly shuffled off to the background afterLinearSolveFunction[]
(which does store the decomposed matrix in the same format internally) became available. I imagineLinearSolve[]
is smart enough to detect triangular matrices. $\endgroup$LinearAlgebra`LAPACK`LATRS[]
, which, though undocumented in Mathematica, is familiar to LAPACK users. The usage is a bit cumbersome, tho. $\endgroup$LinearAlgebra`BLAS`TRSV[]
, which might be used internally byLinearSolveFunction[]
. $\endgroup$LinearSolve[]
is apparently opaque to this. $\endgroup$SparseArray
. This is fundamental to my question. I should have put that in the title. Also this problem come from the discretization of a PDE so $1000 \times 1000$ would actually be on the "small" end of things. The dimension of the problem will be more like $100,000\times 100,000$. How should I address this? $\endgroup$