I'm building a reasonably huge matrix with this constructor:
var M = Matrix<double>.Build.Dense(N, N, (i, j) => SomeRoutine(i, j));
N
is big and SomeRoutine
is slow, so I'm trying to optimize things here and there. I noticed that for any i, j
holds SomeRoutine(i, j) == SomeRoutine(j, i)
, i.e. M
is symmetric, therefore one can define only an upper (or lower) triangle, reducing the number of calls to SomeRoutine
from N^2
to N(N+1)/2
, which is nice.
Here's my approach to this optimization.
var arr = new double[N, N];
for (int i = 0; i < N; i++)
{
for (int j = 0; j < N; j++)
{
arr[i, j] = (i <= j) ? SomeRoutine(i, j) : arr[j, i];
}
}
var M = Matrix<double>.Build.DenseOfArray(arr);
Doesn't seem very elegant to me. Is there any way I could approach the same optimization idea while retaining the lambda-style declaration? Or maybe I should write some sort of wrapper that would mask for
loops?
I think it would be better to split this into two: Firstly, calculate the lower triangle, then in a separate loop assign the values from the lower triangle to the upper triangle. It's likely to be more performant. You might also be able to use Parallel.For for the outer loop (during calculations) to speed it up.
Something like this:
I doubt that it would be useful to parallel up the
CopyLowerToUpperMatrix()
.